Compare commits
2009 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
47b9360d46 | ||
|
98c2a6adcb | ||
|
3b0a9bac75 | ||
|
f6893ed319 | ||
|
a5214c971a | ||
|
ccfcef8c0f | ||
|
1a7a57ed19 | ||
|
eac064bde9 | ||
|
4afc1d85ce | ||
|
818b5f79df | ||
|
8ef60bfa9d | ||
|
d90e0e97fe | ||
|
ec7964e8fb | ||
|
add7ce361b | ||
|
7d16f67d6d | ||
|
e3adb97085 | ||
|
55941823ec | ||
|
07acce8a76 | ||
|
5b1677f21a | ||
|
623c398005 | ||
|
aa92239edd | ||
|
897712c743 | ||
|
02b24d0101 | ||
|
26eadc37a3 | ||
|
6d7156bc70 | ||
|
6312e1720d | ||
|
cb7ae25177 | ||
|
a4adb3f5c0 | ||
|
5cf408ebbb | ||
|
3ca6bb0a61 | ||
|
457a169c49 | ||
|
bad381cebe | ||
|
6171da6d0b | ||
|
067f2a91a0 | ||
|
bc52485570 | ||
|
b20afa275a | ||
|
b096e47f57 | ||
|
4d211e0c9e | ||
|
dffbeac57a | ||
|
0361adc01f | ||
|
1971a9dad2 | ||
|
5dbf4820ab | ||
|
b2eb13a178 | ||
|
2bc9d5ff01 | ||
|
5918cc9f7c | ||
|
15f6e9f678 | ||
|
b5addfe3da | ||
|
7f4246b6d5 | ||
|
6ab82446bb | ||
|
9c93337d97 | ||
|
cdee93ae25 | ||
|
eee3ac092c | ||
|
5bb56ed5ba | ||
|
0aae5eeadb | ||
|
6d994db9d2 | ||
|
cba5484be0 | ||
|
4048dd4900 | ||
|
98556fbe2e | ||
|
f438a36612 | ||
|
e8d966aec6 | ||
|
523532a52d | ||
|
51c640fdbd | ||
|
4cf1bfae0e | ||
|
9642afc468 | ||
|
ffb6c809be | ||
|
64ea9c4d1f | ||
|
a5834fd319 | ||
|
1e9cd9137b | ||
|
d4cd9b3e3a | ||
|
31f1b2c7c4 | ||
|
ce27936ed5 | ||
|
b7f05b9e4f | ||
|
d5761ad625 | ||
|
b26f9d64d6 | ||
|
da80163e24 | ||
|
28396ae345 | ||
|
a0e9f6ed9b | ||
|
bde8cdee46 | ||
|
669e02b4dc | ||
|
52c8683bcf | ||
|
c19eab9691 | ||
|
dd85c54961 | ||
|
c795bf9e4a | ||
|
c469300941 | ||
|
81300052e0 | ||
|
df4e5c6fdf | ||
|
a175a3d902 | ||
|
9cbd768210 | ||
|
c716a07abc | ||
|
c880f02fe8 | ||
|
ce88fa4d4a | ||
|
d734bac590 | ||
|
75a11b05b2 | ||
|
854b5ecbb8 | ||
|
d8073f9b17 | ||
|
46e813343e | ||
|
ad0155b5f5 | ||
|
0856e94ece | ||
|
1c97cdb115 | ||
|
ce2ffdf75f | ||
|
6dd33a8d90 | ||
|
589e0ecd03 | ||
|
037045a054 | ||
|
63bf5b329c | ||
|
dc9dfe562f | ||
|
757928dfa1 | ||
|
a0faa02616 | ||
|
44d76da21a | ||
|
05c6131cf3 | ||
|
001347b4e8 | ||
|
edce11fcb4 | ||
|
e78d589e25 | ||
|
06461cac53 | ||
|
8e94b00587 | ||
|
9245d02bc5 | ||
|
4d41b38a24 | ||
|
29535e6cb8 | ||
|
10126444bf | ||
|
23612720ce | ||
|
f84db7d166 | ||
|
a1d0d0aea4 | ||
|
534158c1cb | ||
|
56dca9880d | ||
|
703f258b06 | ||
|
bce1d2a434 | ||
|
084ddaf81f | ||
|
be9041fefd | ||
|
09bd4af77e | ||
|
7472310a03 | ||
|
27db57f704 | ||
|
1f6f45e6e9 | ||
|
e3e75464fb | ||
|
90322cd4d3 | ||
|
b9cc76058b | ||
|
daa052398e | ||
|
6760974912 | ||
|
e84317ff86 | ||
|
a1a758f13c | ||
|
8dc92e69ca | ||
|
73ac4fcdbe | ||
|
bc6b5cef25 | ||
|
491be8382a | ||
|
329171a950 | ||
|
12b8eac514 | ||
|
2524af80a9 | ||
|
91d79da49f | ||
|
eb52b4e258 | ||
|
278745d6d8 | ||
|
910c87bda0 | ||
|
31b4246e18 | ||
|
a91c4b3869 | ||
|
26d87aa5d3 | ||
|
44145f681a | ||
|
0182de6d18 | ||
|
df25aa9fdc | ||
|
68fc594247 | ||
|
a6a7e8ac26 | ||
|
189d8fab30 | ||
|
e90e438cf6 | ||
|
bf6922b31e | ||
|
27e762d06f | ||
|
b2ae2fdf00 | ||
|
1b78f611d3 | ||
|
e2a136f41e | ||
|
18a0362dab | ||
|
c2b7e2d039 | ||
|
27f8403178 | ||
|
0729a6cc73 | ||
|
d9d5c79644 | ||
|
650e7ad90f | ||
|
7bbab0efdd | ||
|
a920932703 | ||
|
c7935736da | ||
|
7f55399304 | ||
|
5428ac5057 | ||
|
a8cf250c98 | ||
|
ca1fbd5e98 | ||
|
d16ba33dee | ||
|
5eb2867733 | ||
|
048a59310b | ||
|
c88c0d1c89 | ||
|
4a38d39694 | ||
|
841dc28e9b | ||
|
c122a5f14a | ||
|
5cee64514f | ||
|
b40b7e7bf6 | ||
|
6d526cb60f | ||
|
46bed49a43 | ||
|
c769d18cf6 | ||
|
612c5eba20 | ||
|
fe62300223 | ||
|
0b6b14b71e | ||
|
1c3e86dc2c | ||
|
9dc793b0e5 | ||
|
1e6c42594f | ||
|
430182dce2 | ||
|
f710e00d26 | ||
|
53f981f864 | ||
|
a37668e9f5 | ||
|
68c5dd1730 | ||
|
90e15cb706 | ||
|
9475c0b6fa | ||
|
218f8d36b1 | ||
|
d20b385834 | ||
|
b608bb1513 | ||
|
3196f9f0d0 | ||
|
2fc3a43e87 | ||
|
ced24fde7d | ||
|
c6e8ad7a38 | ||
|
47c7450f0f | ||
|
4a5a350f59 | ||
|
b48e34fc3e | ||
|
d40db7cd3c | ||
|
004f57e19a | ||
|
7809447c3f | ||
|
7a1ba51bae | ||
|
9df3e294c3 | ||
|
7fcddef117 | ||
|
c867d392d0 | ||
|
8faeea18f8 | ||
|
c2c67ee34d | ||
|
1e3fc25268 | ||
|
299b7b4370 | ||
|
1e856d4e2d | ||
|
5124e78e05 | ||
|
4d3280e817 | ||
|
8041585379 | ||
|
2a4ecda216 | ||
|
e3df475bda | ||
|
c48feb30f5 | ||
|
1e550b58d9 | ||
|
1e8d9d92a5 | ||
|
7563402631 | ||
|
0be71a8c67 | ||
|
4e6ad1939f | ||
|
c7d3814450 | ||
|
c1ad6115a2 | ||
|
256487c95a | ||
|
2c86e20ab9 | ||
|
683ef1722e | ||
|
79239e3be0 | ||
|
6b58e2e5a9 | ||
|
164f792b86 | ||
|
2aa0218cc7 | ||
|
8d683b560c | ||
|
c449d83790 | ||
|
d6a817f58c | ||
|
ceabd68e28 | ||
|
558eb149f4 | ||
|
3e1e1bd268 | ||
|
aa870debad | ||
|
3e19583b29 | ||
|
9e1dada14b | ||
|
3b4007c9fa | ||
|
bfb54f72a0 | ||
|
6605f217c5 | ||
|
b6d3edb749 | ||
|
f70fdfc612 | ||
|
ec3cdfd17b | ||
|
26b9850d87 | ||
|
98dbf15d0b | ||
|
e8feeabfef | ||
|
0db61198e9 | ||
|
bc8ed4e104 | ||
|
b00b629b96 | ||
|
0761908a77 | ||
|
c579e7337f | ||
|
5ec2551761 | ||
|
5881209f12 | ||
|
5c309f5cb1 | ||
|
7759f9b1c0 | ||
|
51b9c9c103 | ||
|
4318083511 | ||
|
939d954810 | ||
|
76ef6332cc | ||
|
7369bed22c | ||
|
21a5d9ee62 | ||
|
7683a17d69 | ||
|
382d72a26a | ||
|
df33cd0874 | ||
|
be01e7e93a | ||
|
7ee9c64c04 | ||
|
a2fb09021b | ||
|
0cdc51acd1 | ||
|
aa3a9cde6c | ||
|
08a57d3375 | ||
|
2f6de25418 | ||
|
f8f2c7f747 | ||
|
a8151c40c4 | ||
|
f0dee00d33 | ||
|
3fc3880f0e | ||
|
d35a97d28e | ||
|
7d06113cbe | ||
|
c10ceab7e8 | ||
|
d34745a40b | ||
|
264192fd25 | ||
|
79c6e5787d | ||
|
6042222d44 | ||
|
7de6ba7ea9 | ||
|
630798503c | ||
|
f4ff5f337c | ||
|
d8c32b1e82 | ||
|
86176ff770 | ||
|
45a0cd943b | ||
|
99fce8fa19 | ||
|
af2c109079 | ||
|
4ac0940e81 | ||
|
3a87dd0c96 | ||
|
37965a961e | ||
|
9ee956f765 | ||
|
096a067b1f | ||
|
8d9049942d | ||
|
708769b4c3 | ||
|
614f38767e | ||
|
f1f1b0d438 | ||
|
4815f62358 | ||
|
025525f93a | ||
|
debd888cf5 | ||
|
3e73e392a0 | ||
|
fb94ef9e9a | ||
|
628f2fd815 | ||
|
3798d85bd1 | ||
|
2407157d00 | ||
|
7d17e6898a | ||
|
337f3bbff2 | ||
|
9b891e2360 | ||
|
81601d99fe | ||
|
e8deeeae97 | ||
|
5f5080994f | ||
|
60944f1092 | ||
|
a246403137 | ||
|
3f375a4501 | ||
|
e8153f9002 | ||
|
568e037012 | ||
|
31d05de72a | ||
|
f884ab76b1 | ||
|
1117cf052c | ||
|
b69248048c | ||
|
38737a8353 | ||
|
5c1a2fc44c | ||
|
ba3d1de3bb | ||
|
2cec040b9e | ||
|
e9652becfd | ||
|
31a415cc59 | ||
|
024e281252 | ||
|
48b3d5038f | ||
|
cb6ffd06e6 | ||
|
67450d89f3 | ||
|
96c4c208b4 | ||
|
7fd54c56a8 | ||
|
ce0982fefd | ||
|
0c784d434c | ||
|
120be65dbc | ||
|
7598f5a95a | ||
|
d5608fb8a2 | ||
|
a7732e72be | ||
|
6a50d3076c | ||
|
29b055b511 | ||
|
f899fe0b2f | ||
|
d76502d169 | ||
|
787ae317fc | ||
|
e82eb45a74 | ||
|
db4b155c51 | ||
|
72489d5690 | ||
|
2c2f372def | ||
|
e51c269a51 | ||
|
b0bcb30346 | ||
|
ec305903d0 | ||
|
57c4dbf454 | ||
|
30bbb892db | ||
|
b8ecfe2425 | ||
|
9ca382e2aa | ||
|
0c59897da9 | ||
|
b6568d11b3 | ||
|
65c07b75cc | ||
|
a5a89bcf1d | ||
|
32723d229f | ||
|
2aa2ccc90c | ||
|
df8030d9bb | ||
|
42e223f4a6 | ||
|
4dce306a04 | ||
|
e526174009 | ||
|
af89f828eb | ||
|
d03d45fbf0 | ||
|
4184a52c98 | ||
|
ec093d3cea | ||
|
029563a4b9 | ||
|
8d895f13c7 | ||
|
ff34146f57 | ||
|
234f5aff1a | ||
|
a0e11dc817 | ||
|
0bf65ce8b0 | ||
|
557e2f5944 | ||
|
47bf3ab672 | ||
|
315a8a7179 | ||
|
e761e47cd0 | ||
|
71769b9715 | ||
|
ac9e5e91f6 | ||
|
98f0c271fb | ||
|
8560ff9718 | ||
|
ce28575b3a | ||
|
8838199f5c | ||
|
f910d29083 | ||
|
02a7291742 | ||
|
9c37fc5617 | ||
|
a55e1893dd | ||
|
b077013c30 | ||
|
bbb794966b | ||
|
e78eb589d9 | ||
|
04b8633410 | ||
|
aa8c8cac84 | ||
|
a0d4bacbc6 | ||
|
0feda1fa2f | ||
|
45e46bd245 | ||
|
3dc2591517 | ||
|
3d4a27607d | ||
|
fba6ef461c | ||
|
fa86d18353 | ||
|
f47491eaca | ||
|
e4407167ab | ||
|
253213b29d | ||
|
5e1b92cb65 | ||
|
789463ce76 | ||
|
cc688485db | ||
|
cf845be5ee | ||
|
28983d964b | ||
|
0832dda409 | ||
|
4b4b11da57 | ||
|
34d798a0ff | ||
|
811d2f70e4 | ||
|
83d2f30f8b | ||
|
8ea9b14a80 | ||
|
d2ee11f15a | ||
|
a80cd8db06 | ||
|
3b0abe376e | ||
|
090bb3bbea | ||
|
783aa85c1b | ||
|
5ecad1c3d9 | ||
|
659cdd09a0 | ||
|
fe0658dd36 | ||
|
fb237d4fc9 | ||
|
bb825de73b | ||
|
1a699686b9 | ||
|
42e382062c | ||
|
68a6285818 | ||
|
0e845a2914 | ||
|
550e13ae9f | ||
|
b13fae7a9f | ||
|
0aecca3e04 | ||
|
a054073ec7 | ||
|
8ebe5c571a | ||
|
28f7d3694e | ||
|
3bc00c429a | ||
|
87a3c7392b | ||
|
49df9f04e0 | ||
|
26dfc533bd | ||
|
75b658c6c9 | ||
|
24b6a3f357 | ||
|
b21d19d37d | ||
|
b8148b0daf | ||
|
ddc09b161a | ||
|
32f8f20852 | ||
|
a447b3dc1a | ||
|
0cd9ba387b | ||
|
35e44db713 | ||
|
cc8d879a12 | ||
|
77f6168729 | ||
|
a384e749e2 | ||
|
2c6be5afd1 | ||
|
0676e70325 | ||
|
39f7d5a843 | ||
|
fd2c5b9259 | ||
|
39defa27fa | ||
|
be5cdf52c1 | ||
|
37dceed8ec | ||
|
65b4722a1a | ||
|
fcac1a26f8 | ||
|
956c5f293e | ||
|
3e22526ad9 | ||
|
99b00a8cc0 | ||
|
de3300ed89 | ||
|
3dfd2467c3 | ||
|
e5fdda1286 | ||
|
308d7a09a8 | ||
|
9a34caf40f | ||
|
eaae203e94 | ||
|
4282da662f | ||
|
e9846945c7 | ||
|
4b1243fbf8 | ||
|
5e9c7cdb42 | ||
|
01c731e241 | ||
|
92d97a3244 | ||
|
e9670df145 | ||
|
a3d9a685e8 | ||
|
f805a80bc1 | ||
|
62ee36142d | ||
|
b3a713bf7a | ||
|
c4f6c5161c | ||
|
feb376ea1e | ||
|
2139d40e97 | ||
|
55959b5456 | ||
|
666c4fb299 | ||
|
67c5bdfdfe | ||
|
dc8c60f30f | ||
|
80988cd6f4 | ||
|
1f24c47e29 | ||
|
0677a9ae4d | ||
|
a54a12362c | ||
|
e325dbc672 | ||
|
9855d875c7 | ||
|
2bbc4bfbff | ||
|
f57382f885 | ||
|
555973f6b0 | ||
|
902c5e1bd4 | ||
|
1bc9384ea8 | ||
|
36f227586e | ||
|
2d4412316f | ||
|
d7151e0d84 | ||
|
7ef1dcafba | ||
|
f33416949f | ||
|
8dda26af54 | ||
|
0926864ecb | ||
|
9ad3bc9a49 | ||
|
6940875e6e | ||
|
d2083a1aed | ||
|
36545cc92c | ||
|
a54c61e860 | ||
|
fbb759ab82 | ||
|
ab05502494 | ||
|
12febd5162 | ||
|
6c239a7b98 | ||
|
598b86a4cf | ||
|
69831995cb | ||
|
47a1dcc82e | ||
|
0c7091198f | ||
|
bced87cff9 | ||
|
024fc2a1f7 | ||
|
4752863b5b | ||
|
d7bbee35b0 | ||
|
a63dcb46b2 | ||
|
827951dcf6 | ||
|
875d51c1ed | ||
|
664586ea54 | ||
|
4612e79b8d | ||
|
3255b182ab | ||
|
352b9c517c | ||
|
7b93b3d2e9 | ||
|
a7352b1429 | ||
|
ee4d91ea98 | ||
|
68710a6702 | ||
|
6f2b124472 | ||
|
0497a33ece | ||
|
f3cef7e2f0 | ||
|
233c0555c3 | ||
|
c97b8f287e | ||
|
1822e59ac3 | ||
|
fa0ad267b8 | ||
|
6ae6ea587b | ||
|
199c2a0961 | ||
|
77a32398e5 | ||
|
6dc8b57ca4 | ||
|
07f6e6afc2 | ||
|
eab07b4a61 | ||
|
de493ba959 | ||
|
9dd1555c81 | ||
|
8c7984d201 | ||
|
b64b8f375a | ||
|
831606a4e9 | ||
|
cc7cd78e5b | ||
|
16be3af03c | ||
|
b89ed7ff15 | ||
|
17045d5d3a | ||
|
7904d9c002 | ||
|
7a7ffc2c19 | ||
|
65fe6c9735 | ||
|
c311d8bde9 | ||
|
1e692094be | ||
|
7332e633dc | ||
|
2ed0d042a3 | ||
|
a76e307176 | ||
|
6886665f65 | ||
|
703ce5c223 | ||
|
ad7ab67571 | ||
|
9fa9adbd58 | ||
|
3b560044bc | ||
|
82664b4e6b | ||
|
fbfbaff540 | ||
|
e4a68d776f | ||
|
9b08a716d6 | ||
|
554251cc72 | ||
|
17d31d94b7 | ||
|
a5b62aa82e | ||
|
b181026e58 | ||
|
4cc9c2d3e1 | ||
|
f34be230aa | ||
|
a189c9ab8a | ||
|
51463209a8 | ||
|
7ac840090e | ||
|
61d12f1668 | ||
|
f21621e677 | ||
|
88425160ae | ||
|
b9001f4ec7 | ||
|
4329739d3e | ||
|
90d55956d0 | ||
|
51ae8a41a1 | ||
|
f962eab27a | ||
|
381ff1a421 | ||
|
43269920db | ||
|
f56df8b8be | ||
|
ccfcfb116d | ||
|
4dabea37af | ||
|
0516d599cf | ||
|
b5191caddc | ||
|
0c7898c55a | ||
|
289ceac222 | ||
|
e25f83d629 | ||
|
e6835795f0 | ||
|
b6005cc8a0 | ||
|
95039ea3b3 | ||
|
ca073db5b6 | ||
|
c3a295e9b7 | ||
|
c47aa0cea1 | ||
|
c1b8250300 | ||
|
a763d47bc7 | ||
|
a3101e9744 | ||
|
c26672e281 | ||
|
26bb10a486 | ||
|
41b0c21322 | ||
|
87a5479ff8 | ||
|
b4ef38c064 | ||
|
ce7bea66cf | ||
|
1a9d1e8b71 | ||
|
55add063c5 | ||
|
9228d2637a | ||
|
8f1826d3e4 | ||
|
badee3274b | ||
|
e149fd4f70 | ||
|
7e9b97007e | ||
|
1baa91f852 | ||
|
22874e2388 | ||
|
3511991e2f | ||
|
9a51d513f2 | ||
|
3d15454097 | ||
|
4641da06ac | ||
|
b7dca0ed16 | ||
|
a1c382c8ce | ||
|
8b53be49f3 | ||
|
bf741a46d6 | ||
|
652ca302cb | ||
|
93a240b8ad | ||
|
5e8f5eaa50 | ||
|
fc68113d75 | ||
|
4b43de963e | ||
|
588e0f194a | ||
|
ab12b2aa8e | ||
|
98cb7ccf67 | ||
|
75c0deac1f | ||
|
54f88531d4 | ||
|
340aef5362 | ||
|
379fce2d77 | ||
|
c750b18f60 | ||
|
2f57564f5d | ||
|
2b68925ec9 | ||
|
0ee47e0186 | ||
|
5480b288e8 | ||
|
5caa8a25f7 | ||
|
6fae0b4b23 | ||
|
f70aa4939f | ||
|
cd3432e594 | ||
|
b90e566e1b | ||
|
0c25782036 | ||
|
6dad6cd919 | ||
|
dd4c3968d1 | ||
|
dc71987fca | ||
|
871f31353b | ||
|
2db7ffbaab | ||
|
61070cb367 | ||
|
f8ec709e33 | ||
|
cda7bca126 | ||
|
6e2be38ae2 | ||
|
986f7f5d64 | ||
|
1591980579 | ||
|
591e494dfd | ||
|
f19754cfa6 | ||
|
24ab5ca85b | ||
|
1b8e31b70c | ||
|
ffe0b57faa | ||
|
a4521208ba | ||
|
3989c40da6 | ||
|
a6f2ab9d93 | ||
|
bfc6c1e6e0 | ||
|
36817f3774 | ||
|
df4c93b3e8 | ||
|
c90c057e12 | ||
|
e9a10d66b7 | ||
|
5e2ddb890a | ||
|
1300b64bb9 | ||
|
228cea4af1 | ||
|
254615509a | ||
|
993d5c5707 | ||
|
7d2b7126db | ||
|
802e5b5547 | ||
|
67a2b75fe6 | ||
|
cb227cc3a1 | ||
|
a0d030a7ae | ||
|
193f721c7b | ||
|
7065ff5586 | ||
|
aeb9b99a6c | ||
|
877eca691c | ||
|
63ede7e406 | ||
|
c6feef6c86 | ||
|
350d8e5995 | ||
|
ba8fd17394 | ||
|
9fb713d804 | ||
|
b7761e9a2e | ||
|
789e3883d6 | ||
|
7da837b42a | ||
|
e6c5da315e | ||
|
258946cd88 | ||
|
068f33aaef | ||
|
dec3642905 | ||
|
fdd3292f09 | ||
|
3549da0dd1 | ||
|
e5c1147cf6 | ||
|
5bf6a1479c | ||
|
a78f254611 | ||
|
d7909a77aa | ||
|
f6953e1317 | ||
|
10e06c15c9 | ||
|
7b7c8a1b02 | ||
|
a06edb9deb | ||
|
768b2ba0f5 | ||
|
d73b86b4b7 | ||
|
bb9560716d | ||
|
cc4671d7a1 | ||
|
47ad6f4b59 | ||
|
aba7b987d3 | ||
|
b6477ea7ae | ||
|
01142e6dd8 | ||
|
bbb6afaf46 | ||
|
9486ec7cc4 | ||
|
476b431041 | ||
|
877bf59cb6 | ||
|
ca4009c982 | ||
|
d7118fda70 | ||
|
2827af33d6 | ||
|
867e63b524 | ||
|
0d435e2435 | ||
|
7b1ba3f269 | ||
|
d1b3695282 | ||
|
f61539c4e7 | ||
|
9a944637be | ||
|
4bd19160de | ||
|
b3be9eb869 | ||
|
0b71559017 | ||
|
e2b4de9d95 | ||
|
d7ed452d69 | ||
|
5536b836ad | ||
|
ffdc98d024 | ||
|
381c5d1a76 | ||
|
5683be0ea3 | ||
|
9e28de70ec | ||
|
d2cb7a9ce9 | ||
|
0cf24219d8 | ||
|
e132c79348 | ||
|
edbdd08476 | ||
|
454682979e | ||
|
f293c5e9c0 | ||
|
dcab540839 | ||
|
2f16eadb35 | ||
|
6f9f2189f2 | ||
|
6f49194640 | ||
|
0ffda8aaf0 | ||
|
34c088882b | ||
|
f8d2bd13b1 | ||
|
d851f10a48 | ||
|
356dcef9e8 | ||
|
7352d66819 | ||
|
64b1572d13 | ||
|
7374b29364 | ||
|
b0be808036 | ||
|
9c593bde89 | ||
|
44d3433ea9 | ||
|
7ee624844a | ||
|
b48a1b3a5d | ||
|
d8618b0682 | ||
|
af93cfb32a | ||
|
acfc759527 | ||
|
760f7a649a | ||
|
2d6ce1a5fd | ||
|
43db1965ef | ||
|
61df2956b3 | ||
|
83a531bc89 | ||
|
2e50573531 | ||
|
5e3aec6df2 | ||
|
371eed1f93 | ||
|
77a866129b | ||
|
c5f67a31dc | ||
|
ed56093888 | ||
|
34f8f8b30d | ||
|
fe7edce569 | ||
|
b7c938c239 | ||
|
f35517b3ff | ||
|
cbe593503f | ||
|
f72877bf0d | ||
|
7165fa949d | ||
|
519c90a887 | ||
|
5bae422b29 | ||
|
b8bd0e4c6a | ||
|
45e8503ead | ||
|
8456c050ea | ||
|
54fda21366 | ||
|
d7cfff324e | ||
|
622a849bae | ||
|
462d494ed8 | ||
|
442b1d5cc2 | ||
|
5f8c6470ff | ||
|
948d1bcac8 | ||
|
1178b475da | ||
|
286cbf32a7 | ||
|
4606607309 | ||
|
0b39b0fc5f | ||
|
61a51df1b2 | ||
|
332e187813 | ||
|
a1ba91b01d | ||
|
eb5aa14a6f | ||
|
911e60cf5c | ||
|
994cb95893 | ||
|
0e6d549a40 | ||
|
6a576f0121 | ||
|
0062f61d67 | ||
|
427c4c8b44 | ||
|
4f25410aa9 | ||
|
860a5fca8f | ||
|
d8cb2218ee | ||
|
e66178ff9a | ||
|
99b17b0ac4 | ||
|
e02df8d550 | ||
|
79ce5ad8b0 | ||
|
b0b0b186f5 | ||
|
f5b5ac7183 | ||
|
71f993b25d | ||
|
83f8dd50df | ||
|
f980d4b926 | ||
|
adcdb080cb | ||
|
5e942c9a67 | ||
|
958fb4c8e0 | ||
|
cfcfe8866c | ||
|
35237a4f88 | ||
|
da1e078242 | ||
|
a1ec5d9ad7 | ||
|
e68fe81938 | ||
|
b21f00c29d | ||
|
67680bd2d5 | ||
|
addb473148 | ||
|
fe44fd7c3b | ||
|
7bc6a62365 | ||
|
ba684962b6 | ||
|
f9379dc6bb | ||
|
7e254955e8 | ||
|
ebbb7492e7 | ||
|
27c977adb2 | ||
|
428243bb78 | ||
|
ac2b4f8d12 | ||
|
aec2be6da2 | ||
|
2bebb96804 | ||
|
551598e0a4 | ||
|
42044e4279 | ||
|
ec4315dfbe | ||
|
5bb616832e | ||
|
c080569cac | ||
|
2f0c6dcfa3 | ||
|
9112c4f32f | ||
|
0d82cd1e6c | ||
|
171bae1f5c | ||
|
c120aa0274 | ||
|
b650bef139 | ||
|
97593958e4 | ||
|
f3d9c2f610 | ||
|
7bfd3e1c6a | ||
|
da2e8220f3 | ||
|
ecda5c1df9 | ||
|
1756c01522 | ||
|
6f08ef2a07 | ||
|
c0d323828e | ||
|
f87af06ad6 | ||
|
30e90b2425 | ||
|
334849e2a6 | ||
|
107fdda1f0 | ||
|
6850fd40fe | ||
|
21f54b9e12 | ||
|
9c10ddae3b | ||
|
526152b9c6 | ||
|
81bba1b587 | ||
|
4eae5d2e6d | ||
|
87df97317f | ||
|
b96afce222 | ||
|
6da9236ffd | ||
|
03d9c51b5d | ||
|
7e68901ceb | ||
|
1bd537c350 | ||
|
f8b35078fc | ||
|
b61a6ab758 | ||
|
8d43c4344d | ||
|
325c8061ea | ||
|
6d8319e1bd | ||
|
70b2b8a1bf | ||
|
dc1918b217 | ||
|
7453bc8f44 | ||
|
b441181c18 | ||
|
ea946f2492 | ||
|
c898f35959 | ||
|
d6a5695f8a | ||
|
0126880dad | ||
|
b3c1471180 | ||
|
1f60526ab8 | ||
|
14389326b4 | ||
|
eb282e49d9 | ||
|
2e4fb5b91c | ||
|
d6510360d0 | ||
|
554d3209db | ||
|
72638aa03e | ||
|
3516704b82 | ||
|
a9d01af104 | ||
|
1cfba83164 | ||
|
e16bfd7837 | ||
|
11136f7d7b | ||
|
112ce5299e | ||
|
86dde85b2d | ||
|
e2feb41605 | ||
|
fef819fbb9 | ||
|
f75579de7e | ||
|
77cac3b30d | ||
|
344ed4f42e | ||
|
a27757682a | ||
|
b72bcafecd | ||
|
45b832bfdc | ||
|
dd7522bd9f | ||
|
c3e1b2afef | ||
|
64ca77f3a5 | ||
|
33cca46346 | ||
|
dd78d230ea | ||
|
c286668b79 | ||
|
9bd28321e5 | ||
|
fd58d31eea | ||
|
46e908c06e | ||
|
2ace9385a2 | ||
|
5583748b54 | ||
|
f1bf70a4a2 | ||
|
bc1e2f5276 | ||
|
5d37530687 | ||
|
bc5b01d4d8 | ||
|
d239207f0f | ||
|
3187a641cf | ||
|
329cc9ee48 | ||
|
3b327378eb | ||
|
f4f5b4e65a | ||
|
5f27616f32 | ||
|
05f54d098c | ||
|
599ca960aa | ||
|
cd0e48234a | ||
|
5b58c7e15b | ||
|
9ed3baf004 | ||
|
9705b39c2b | ||
|
19b5050fbf | ||
|
b0c14bd59f | ||
|
1cf86e12a1 | ||
|
d75a18e603 | ||
|
02cd424d18 | ||
|
4d7191147c | ||
|
ebc6b9429f | ||
|
139251ea73 | ||
|
3f6acb6378 | ||
|
b1d050285a | ||
|
8ca6ff3a94 | ||
|
35eebe8553 | ||
|
7f9e61a1f2 | ||
|
555126441e | ||
|
cfd69cd122 | ||
|
5f547fb118 | ||
|
575ff91369 | ||
|
5f5b4ea8eb | ||
|
08f854ffef | ||
|
c543adddb2 | ||
|
053d9d420c | ||
|
4e5a7e97ad | ||
|
9a5b5574a8 | ||
|
5d56985479 | ||
|
e37fb1dad9 | ||
|
57428a95aa | ||
|
4fb17d5610 | ||
|
876516a1fb | ||
|
b21aef565b | ||
|
fdd17e3042 | ||
|
c0b2871b31 | ||
|
b7257d9ae4 | ||
|
5e5f1fcb3e | ||
|
5b612b856a | ||
|
86b09c8cf7 | ||
|
3633af5e41 | ||
|
df29735c83 | ||
|
d39757b4dc | ||
|
ebc731aaf3 | ||
|
81a0e66d9f | ||
|
7eb4e22515 | ||
|
a74d6a2aaf | ||
|
e2455d6f26 | ||
|
cafcd90f9f | ||
|
a14832c4da | ||
|
df770ae4ea | ||
|
b37e73488f | ||
|
dc5245025e | ||
|
dcaf7b2c21 | ||
|
db85163e20 | ||
|
8c844e6eab | ||
|
822a6c6b9d | ||
|
61c16a89d2 | ||
|
d562cb7648 | ||
|
0f78b01e81 | ||
|
11605ff5ed | ||
|
93b3eebc5d | ||
|
66ffda24f0 | ||
|
5295886f68 | ||
|
7c191d7be0 | ||
|
f72de10328 | ||
|
ff6c4b04f4 | ||
|
1b81549c97 | ||
|
37236207a0 | ||
|
76a6e41031 | ||
|
e3d8c3fa12 | ||
|
6322874d3a | ||
|
e4f4761c87 | ||
|
798ba1e5be | ||
|
89912dc657 | ||
|
a514f03fd4 | ||
|
d201344443 | ||
|
2c12c12850 | ||
|
aa6d81d6f9 | ||
|
a75bca1e95 | ||
|
fc599d2aec | ||
|
493fa4df16 | ||
|
c4c32264bf | ||
|
fc15850288 | ||
|
a8174eeac9 | ||
|
ed8a32f98b | ||
|
625eee0caa | ||
|
e139b20d12 | ||
|
f7990af6d0 | ||
|
da0fc1a6d8 | ||
|
025fc0525f | ||
|
233f5e27e2 | ||
|
b9f8e13d80 | ||
|
bbafa00df0 | ||
|
d33bd8deff | ||
|
15f6c4f3dc | ||
|
95be88be19 | ||
|
012a3497eb | ||
|
caedf26a06 | ||
|
9487eb2dc9 | ||
|
c49c57ef30 | ||
|
bb527f30f8 | ||
|
c8eaa91ad3 | ||
|
d35cc7a83e | ||
|
3c7a09f52b | ||
|
1d0e63b251 | ||
|
9200bc789f | ||
|
e4dd8de4f1 | ||
|
afb554a014 | ||
|
f559701645 | ||
|
4e80960933 | ||
|
d2102e5705 | ||
|
c5f674340a | ||
|
fc071fd1af | ||
|
99e6f89eba | ||
|
b0d9bbc121 | ||
|
27cf97cb9e | ||
|
6400af605e | ||
|
ef18f858cb | ||
|
c53575b18c | ||
|
eec3607b16 | ||
|
d3c5a8a050 | ||
|
eb73563445 | ||
|
d85f61deaf | ||
|
1c404d1881 | ||
|
944857d130 | ||
|
7b8d250bd5 | ||
|
9dcddd1947 | ||
|
50d2dd51cb | ||
|
6236eb8f98 | ||
|
b608d2266b | ||
|
3fdd1e973a | ||
|
7857dd0a9a | ||
|
07db9808a0 | ||
|
60141175dd | ||
|
f504b1a5e8 | ||
|
5b748a4b42 | ||
|
06a5043442 | ||
|
f311c23ffa | ||
|
78dbf64416 | ||
|
3a46fffe44 | ||
|
6c484c1efd | ||
|
7f3b985cc6 | ||
|
69d8d87ec9 | ||
|
a56a7207ac | ||
|
d51e92eb31 | ||
|
0474f86c46 | ||
|
836fc3eaa0 | ||
|
e5a1b4d8ae | ||
|
d9c1ce7738 | ||
|
a5efbb5933 | ||
|
650f7a0a32 | ||
|
041fcc4651 | ||
|
711cdd6929 | ||
|
05dfb1a6ae | ||
|
ed77114038 | ||
|
8c24c77d55 | ||
|
af4d762147 | ||
|
89b9a905db | ||
|
df718395e8 | ||
|
193051dfd5 | ||
|
070bd25721 | ||
|
770a2805e4 | ||
|
ca3563a38e | ||
|
584c108d1a | ||
|
57ee384180 | ||
|
03403e3ea5 | ||
|
e7fc8a0d98 | ||
|
9993684205 | ||
|
1e3d82cc63 | ||
|
f693b02e12 | ||
|
75019f5e4b | ||
|
8ab7e56972 | ||
|
f42f05aab7 | ||
|
9ee224f2ca | ||
|
9da27ad578 | ||
|
2146200dfd | ||
|
6d2cfdabf8 | ||
|
8024f13458 | ||
|
04205a9b97 | ||
|
58e26eb312 | ||
|
0e5498fc83 | ||
|
79b3b1029c | ||
|
4b7c679808 | ||
|
d88b5d1011 | ||
|
2a91e2ff2d | ||
|
a04022883c | ||
|
008ba46597 | ||
|
691a3ab840 | ||
|
10180095d8 | ||
|
e4ce7b0eeb | ||
|
19f7424c62 | ||
|
87fba523ee | ||
|
11bf6f05c4 | ||
|
eaa71f5717 | ||
|
48fc4afc5b | ||
|
69caa9936b | ||
|
d3fa5e7fbd | ||
|
228874804e | ||
|
09099050cb | ||
|
da8636ef54 | ||
|
af8ef9f526 | ||
|
37fe3548de | ||
|
8833c0dd79 | ||
|
2ac1f14973 | ||
|
3b0b36ad5d | ||
|
1081131aa5 | ||
|
457c48ec71 | ||
|
4dd41fa7d2 | ||
|
e910dcbfcc | ||
|
aba2b46a7c | ||
|
61896e829c | ||
|
114f5b23e3 | ||
|
8cc9a47e5c | ||
|
039a1c52e4 | ||
|
ddc1aa0b5f | ||
|
516c4a0593 | ||
|
cbca2f169b | ||
|
6a3ce58ab7 | ||
|
adf9db7454 | ||
|
2c2824fc5b | ||
|
145762a2b0 | ||
|
fe8771e181 | ||
|
240e18cd92 | ||
|
ae7e8d3890 | ||
|
1a96c5b415 | ||
|
1d5d8784b3 | ||
|
cf05eca68b | ||
|
6a1db08299 | ||
|
da7b77d2ec | ||
|
de9b8d6d2c | ||
|
72284cfc7c | ||
|
1f8dbb265e | ||
|
270d51d4d4 | ||
|
98a5faaa77 | ||
|
dbfb782dd5 | ||
|
c8fca94899 | ||
|
c4903a8e36 | ||
|
3ff8323153 | ||
|
08ce4331bb | ||
|
eb5ef5a027 | ||
|
3157361077 | ||
|
f85978e43a | ||
|
e27996b199 | ||
|
af46b484dd | ||
|
3f7ccb6b9a | ||
|
d371f2d9ee | ||
|
fb8a2766da | ||
|
c344aa854f | ||
|
9218a79e62 | ||
|
cf01d0d634 | ||
|
821feeabb0 | ||
|
58b85da8f2 | ||
|
f23133043b | ||
|
a808a6b177 | ||
|
4fe5d7f642 | ||
|
6939142d2f | ||
|
2703c5afff | ||
|
6449f047e5 | ||
|
0fb567bb53 | ||
|
12d29569a6 | ||
|
d40b2d8153 | ||
|
c796787f25 | ||
|
077cc84d27 | ||
|
4f4643dd2f | ||
|
a78d52e615 | ||
|
0210b7dc6b | ||
|
cd8646b38f | ||
|
a7ee5edd8b | ||
|
12cde5d520 | ||
|
7a4b737a3a | ||
|
0ea95822bc | ||
|
da81d16c27 | ||
|
bf2a5885d0 | ||
|
5a68f932d6 | ||
|
1537e475af | ||
|
17093a8149 | ||
|
d23a22b7c6 | ||
|
3fc43fba37 | ||
|
4da4ce7279 | ||
|
a6e3f19bf7 | ||
|
09c493b39c | ||
|
fc6f36150f | ||
|
d831a4b9df | ||
|
075c770432 | ||
|
701268271d | ||
|
135514a0d2 | ||
|
0d0f6b9c69 | ||
|
6695da4b16 | ||
|
b796b2c933 | ||
|
6c1eeb96b0 | ||
|
073fbe684d | ||
|
b9faca923b | ||
|
c79b303237 | ||
|
c6f6bb67f0 | ||
|
fb298acdcd | ||
|
86493dda93 | ||
|
941fd9659a | ||
|
dc6cae46ca | ||
|
9a51675e32 | ||
|
1a5f48961c | ||
|
f353411460 | ||
|
ea6b094e24 | ||
|
a72531b65c | ||
|
2de7d017f5 | ||
|
3f2cdb1971 | ||
|
bd3d482ade | ||
|
5d5fbb4d45 | ||
|
070d46b096 | ||
|
5d1de67a0c | ||
|
b7e0e080da | ||
|
b8f4f19c36 | ||
|
67a5d9a5dd | ||
|
6bd19b6ac6 | ||
|
440668a78a | ||
|
48ebbe95ea | ||
|
5d2c9676f4 | ||
|
396eaa21f2 | ||
|
6645e858ca | ||
|
4c06d755f9 | ||
|
45adc63597 | ||
|
d7a604c8b2 | ||
|
a1886f51bd | ||
|
8cd98b5298 | ||
|
52ccd276da | ||
|
6131ad0341 | ||
|
234f98705e | ||
|
f641d91b55 | ||
|
9e6e4e520c | ||
|
7a65a63aa9 | ||
|
98b92f0900 | ||
|
9d2bb31a9d | ||
|
eee928548d | ||
|
0ef87c443b | ||
|
5d2cfb7f25 | ||
|
e5b3af8ffe | ||
|
0611bd1c45 | ||
|
cf9aeef83b | ||
|
6c05dc026e | ||
|
6d4b7a94f6 | ||
|
1fef1f4461 | ||
|
8b08a0e444 | ||
|
7759210f29 | ||
|
e0e42e8aa8 | ||
|
68fdd4d290 | ||
|
bb13105338 | ||
|
40cc1536af | ||
|
6101be6234 | ||
|
2a55474c92 | ||
|
c61037c4a6 | ||
|
ecc3a7d49b | ||
|
78e6215cbd | ||
|
0ea047ea25 | ||
|
574bec859a | ||
|
4a29979667 | ||
|
cb93d42dea | ||
|
406a58de35 | ||
|
4ea5f163f0 | ||
|
8fc4cc928d | ||
|
7c3430ba0f | ||
|
6436996eb7 | ||
|
c12e26404a | ||
|
2421fc2f11 | ||
|
168359344e | ||
|
a1fc5bc733 | ||
|
12d575b8e6 | ||
|
9d6d2aeba7 | ||
|
ca2b426252 | ||
|
a46ce4cc3b | ||
|
1817ef4ce0 | ||
|
16a8b9b94b | ||
|
bed38cec71 | ||
|
0c3d89fe17 | ||
|
a23bf783a9 | ||
|
9e2adf5b6a | ||
|
13fbb7f878 | ||
|
5ce9b1a32f | ||
|
3c459100d7 | ||
|
3a3de3e87d | ||
|
701e44a0cb | ||
|
4f84be1c31 | ||
|
b6a988fcb1 | ||
|
4326029984 | ||
|
96f853d8ff | ||
|
e92bb2c824 | ||
|
2a0d2445c1 | ||
|
996f1a8ec2 | ||
|
69ab054323 | ||
|
0c48096147 | ||
|
f73822d348 | ||
|
4f4f83f9a7 | ||
|
78a696a86f | ||
|
4734d15fb6 | ||
|
1ad99a312e | ||
|
59e66ddc77 | ||
|
0641ccf601 | ||
|
425f7baa2b | ||
|
69ddeeb06d | ||
|
96dc9512bb | ||
|
72fb8ffdfe | ||
|
4e17e4837d | ||
|
c1fdbca62b | ||
|
995b6d669a | ||
|
402b039384 | ||
|
0d29694afc | ||
|
0be04ea54d | ||
|
1c2890b47c | ||
|
ad00cce0ad | ||
|
260d0cd340 | ||
|
533a47f06d | ||
|
320f564daf | ||
|
8ccf61e6b1 | ||
|
f1d4393eb8 | ||
|
1393358469 | ||
|
46bdf0692f | ||
|
5030c0603a | ||
|
166eba11b7 | ||
|
4e4dbd6a2d | ||
|
9d5871a3c8 | ||
|
63cd2ce512 | ||
|
86806a3759 | ||
|
503ffb0d45 | ||
|
1088332376 | ||
|
ac94fd4cd0 | ||
|
9cd89e6580 | ||
|
4fdcfebf25 | ||
|
36cc9f492f | ||
|
21ab9d765d | ||
|
ec93a2989f | ||
|
fa3565e617 | ||
|
9ae667e6bc | ||
|
055aa1b059 | ||
|
2b8e1555c6 | ||
|
82fd6a279b | ||
|
46b29edc5f | ||
|
92e2f4e420 | ||
|
a64c3e0179 | ||
|
88b422987e | ||
|
c7bf4f78ab | ||
|
66859010e7 | ||
|
7e3c28a1c2 | ||
|
7e2aea5765 | ||
|
facc0a794e | ||
|
f611ea7b65 | ||
|
bdbe1df43c | ||
|
60bf39f828 | ||
|
ba673c52b0 | ||
|
e777faac4c | ||
|
87bceac9ff | ||
|
5b4a02e8a5 | ||
|
f4b8c70f79 | ||
|
4da3bef4ec | ||
|
ecbb6fc6b3 | ||
|
f97a681f1d | ||
|
1cb4325422 | ||
|
0a1f01ce3f | ||
|
0fb8a49e62 | ||
|
7c3d108e21 | ||
|
e57c9ddd86 | ||
|
0a4bfc95d1 | ||
|
8c37db8a07 | ||
|
176ff96a26 | ||
|
3614c48240 | ||
|
5a3bc7ab04 | ||
|
1dfdcec34c | ||
|
ec2524eb97 | ||
|
55f5d1cca3 | ||
|
c336ce39e2 | ||
|
b63763cf53 | ||
|
89f6bd4fae | ||
|
db82c6fa02 | ||
|
3997e44810 | ||
|
de78a6efed | ||
|
8d14118469 | ||
|
1fedb71f76 | ||
|
fd430e8b69 | ||
|
a1822c5a2c | ||
|
0a5e57362e | ||
|
534d0e580e | ||
|
67a0a1fe46 | ||
|
fc71dcadb0 | ||
|
81ebfbb5ca | ||
|
4e2b90cc0a | ||
|
2e73e5eef9 | ||
|
fc40e9f14c | ||
|
f5f77fea35 | ||
|
e2030c03d0 | ||
|
86eb9c4b8a | ||
|
32779ee15f | ||
|
9d43e22592 | ||
|
0361dd2392 | ||
|
c50561ef10 | ||
|
73bf5ce6f4 | ||
|
acf2d2b004 | ||
|
399f97542a | ||
|
e3d1af1953 | ||
|
570bcc3822 | ||
|
770fec0d88 | ||
|
812f8b8cbf | ||
|
8ed0cd5f16 | ||
|
2798536a7a | ||
|
be0a9e728f | ||
|
c16832f11a | ||
|
e298975918 | ||
|
e74ea54eb9 | ||
|
710edc03ff | ||
|
ecf3a0302a | ||
|
2f93e6ce67 | ||
|
c4f7bae10b | ||
|
3d67598ec9 | ||
|
59844d8e59 | ||
|
7575506443 | ||
|
cb1d5e03b5 | ||
|
0f467a5d51 | ||
|
96b3dd4e7c | ||
|
f9f08627ff | ||
|
1ce39306cb | ||
|
1a3e1465fa | ||
|
c37eda37fd | ||
|
38c431e8a2 | ||
|
9eddaeee3d | ||
|
9a5b503da5 | ||
|
17df235c4e | ||
|
a8cba53537 | ||
|
d94915c515 | ||
|
19ac6e8286 | ||
|
09a4f4da39 | ||
|
0676a7a51c | ||
|
6fc208554d | ||
|
a3fef4c1fc | ||
|
dc2feba72c | ||
|
bd5bd29ec0 | ||
|
a5ec24c17b | ||
|
3a972d4845 | ||
|
21c568c0b4 | ||
|
960ee263e8 | ||
|
a24152df02 | ||
|
79181567e5 | ||
|
80b3d51a49 | ||
|
1d4e6ce924 | ||
|
2e93499383 | ||
|
19814a4c8a | ||
|
e3d0c5e5ef | ||
|
ba9c1a2efd | ||
|
83beccf7e4 | ||
|
bd84315824 | ||
|
a15a86ed00 | ||
|
3661cadf4e | ||
|
d29d5bbc99 | ||
|
f535ccfb54 | ||
|
578bedcd07 | ||
|
8ff8ccc92b | ||
|
5149d6d5c4 | ||
|
083e48d089 | ||
|
8c0a9b8bc5 | ||
|
088f1dfede | ||
|
96104c099b | ||
|
dea754d846 | ||
|
36b625818d | ||
|
d1642cbcba | ||
|
ac78b7a7a5 | ||
|
160453c3e9 | ||
|
9407f8bcde | ||
|
a0197ee2c2 | ||
|
696c3c3184 | ||
|
314d66727a | ||
|
899cdb4c00 | ||
|
4634ce391a | ||
|
f286bd92c7 | ||
|
23af2d3041 | ||
|
f842d1c0a4 | ||
|
91197ffad2 | ||
|
0e5a7bb5c2 | ||
|
d530d92651 | ||
|
a926a6dc3b | ||
|
1f54ea10dd | ||
|
c850744faa | ||
|
5e5186be07 | ||
|
652ea5ddf9 | ||
|
35746efca8 | ||
|
9253d877a2 | ||
|
4faf1829d2 | ||
|
3f51d3da02 | ||
|
3a4aec3708 | ||
|
fa43a94e02 | ||
|
7c2766b34b | ||
|
075b7ffba9 | ||
|
a236e92444 | ||
|
8f6a585b09 | ||
|
a101838162 | ||
|
d59a6ebf62 | ||
|
a14e0fa3fb | ||
|
60dec61c51 | ||
|
e750ca9499 | ||
|
b8c5ccb321 | ||
|
1787683f1b | ||
|
aac4efa955 | ||
|
6f264f9c31 | ||
|
3c572501a9 | ||
|
d4d2fe06d9 | ||
|
fc5ad6c9cd | ||
|
993e8583a6 | ||
|
12f166c0fc | ||
|
5a6c16ab24 | ||
|
8ce5e1cab2 | ||
|
5a9d68a896 | ||
|
c95613f8b7 | ||
|
2f58469f1b | ||
|
51aaa193f2 | ||
|
eadc3a91a9 | ||
|
6764196527 | ||
|
8ca77c1c78 | ||
|
9191e264f8 | ||
|
d2ca12e88b | ||
|
e573e59e83 | ||
|
21d700f633 | ||
|
70ce9fa96a | ||
|
432eb57b13 | ||
|
9e8790cbba | ||
|
e7ada26f55 | ||
|
36cabe3d09 | ||
|
4e50603404 | ||
|
6da0c0e0b4 | ||
|
5f83900ed8 | ||
|
7f0b0ab1ef | ||
|
967affa883 | ||
|
551398ae53 | ||
|
38f1e87334 | ||
|
05e8bf3195 | ||
|
f6feec8c84 | ||
|
f5109fe34e | ||
|
c3584c8d04 | ||
|
880553bf3e | ||
|
58b545293f | ||
|
4c62b60f71 | ||
|
d484a98876 | ||
|
41a21c9b0c | ||
|
63e9f2bc34 | ||
|
e625a7a887 | ||
|
8e8b632716 | ||
|
f7b30414fb | ||
|
4d443efe0f | ||
|
b3b5a65923 | ||
|
39fd2c152f | ||
|
b169ea0f6e | ||
|
ed44e0c4b0 | ||
|
26bdd9bc38 | ||
|
d595d96304 | ||
|
1e4a83b3da | ||
|
cb8fe46328 | ||
|
9e7663463f | ||
|
c9346014df | ||
|
e42566816c | ||
|
15f7fedfea | ||
|
873a7a3211 | ||
|
48143f6a0a | ||
|
cb70c6e8b9 | ||
|
0d984f3886 | ||
|
12d5c315bb | ||
|
bbceed5200 | ||
|
f393561925 | ||
|
03f9cde27c | ||
|
14522dab22 | ||
|
7653fa106e | ||
|
cd006a4066 | ||
|
1726af0c97 | ||
|
dd0cecc7ea | ||
|
c3a487f9ec | ||
|
3734a68a42 | ||
|
5ae0da65e1 | ||
|
62ccd78122 | ||
|
6d2ddd72a5 | ||
|
ea1a34083c | ||
|
76e3b2ebb8 | ||
|
fbe4d53fb1 | ||
|
e8cd669be2 | ||
|
c5fd72bb98 | ||
|
ede0ab1715 | ||
|
d0be90e711 | ||
|
bef52c9496 | ||
|
c42a1dc669 | ||
|
b35a0c3695 | ||
|
897ee16e91 | ||
|
4661f432f0 | ||
|
d9dacedbe0 | ||
|
c68f96741d | ||
|
7c7a68975b | ||
|
d421bbc075 | ||
|
e9fb7a67da | ||
|
0d5355560e | ||
|
6297f11724 | ||
|
8a6a2a1156 | ||
|
88a121f81e | ||
|
b2a356d4b8 | ||
|
cc76f2f4af | ||
|
3f4bac3d04 | ||
|
ad34aa99b4 | ||
|
d42ac5aca6 | ||
|
f49540f436 | ||
|
4bc5ebe7da | ||
|
ff557a7f01 | ||
|
01edd8ccd8 | ||
|
051701d566 | ||
|
528de38359 | ||
|
b869edb0a2 | ||
|
97bfcef20d | ||
|
d03c7452d9 | ||
|
1200a41bb6 | ||
|
6c0cd22b90 | ||
|
6c0862e82d | ||
|
8b6ca810d9 | ||
|
e2ecdbdcf6 | ||
|
858c4450eb | ||
|
93c039fbe1 | ||
|
23885ba778 | ||
|
3e69bc51e7 | ||
|
edd6b9af1c | ||
|
4d9f1bdef7 | ||
|
c7c4010306 | ||
|
7e78ac1eb9 | ||
|
b473ce4f95 | ||
|
5d608b3500 | ||
|
b47cff044e | ||
|
7fdbc45575 | ||
|
63f3652c54 | ||
|
c3e2754ec4 | ||
|
0dddf47af0 | ||
|
f9cc90307b | ||
|
5c6ad497f4 | ||
|
e8b98abfc4 | ||
|
64f47dada0 | ||
|
364987b159 | ||
|
8a91965b07 | ||
|
0f2041ee5c | ||
|
3ebd780872 | ||
|
a1c1fa104b | ||
|
670c6b766e | ||
|
69a7b8c066 | ||
|
6a7b397110 | ||
|
3dddc8c5a4 | ||
|
e7ab5b50ab | ||
|
7cf2005f5b | ||
|
61b01299b2 | ||
|
653751e2f5 | ||
|
9a3a1bdcde | ||
|
602285be35 | ||
|
1211c366bf | ||
|
e03c51c96a | ||
|
3597a20890 | ||
|
0dd4d9b9fa | ||
|
be64fd23c7 | ||
|
092d8533db | ||
|
42dba743eb | ||
|
fdc40a9315 | ||
|
c57abf3411 | ||
|
24cbf72388 | ||
|
dc9092be94 | ||
|
7cb632c5c9 | ||
|
f17fbf28ea | ||
|
4e97843ef0 | ||
|
5cbd9d2262 | ||
|
ab4af86c7b | ||
|
ee9935bab7 | ||
|
afb671c594 | ||
|
487dc3dc46 | ||
|
927ceb99dd | ||
|
47b060d6eb | ||
|
5c4c0378b3 | ||
|
037f5bc514 | ||
|
c02ade76ca | ||
|
a7d57ac3d2 | ||
|
3d888c2eb5 | ||
|
96bae8bd9a | ||
|
08cadba16d | ||
|
59f440209c | ||
|
7aff3a257a | ||
|
f79c661192 | ||
|
8f2d6f2975 | ||
|
d07d8ba2d2 | ||
|
364d2842ab | ||
|
74728d2944 | ||
|
9fceb58444 | ||
|
2e72d4c9e3 | ||
|
3bcb9863e7 | ||
|
08cfde7678 | ||
|
22a307f422 | ||
|
5dc5a9dbca | ||
|
16fd8f6c7d | ||
|
c604777622 | ||
|
62572073b0 | ||
|
cc21092ac2 | ||
|
2d66ae87f9 | ||
|
b0db2c210f | ||
|
b6a2de8a97 | ||
|
adcb887efb | ||
|
b56afd8bb8 | ||
|
f7cb3d56e9 | ||
|
dd2e020351 | ||
|
baf01d5524 | ||
|
26f9070d99 | ||
|
807e3a39a5 | ||
|
254a0dded0 | ||
|
379c4462ca | ||
|
fde6abe98b | ||
|
9edf33da2e | ||
|
29527509de | ||
|
78b7b73e78 | ||
|
1263965511 | ||
|
995373e74b | ||
|
9c2d7f56ce | ||
|
56fa7423f3 | ||
|
859f7d9340 | ||
|
e73ef09fdd | ||
|
8ff071bf04 | ||
|
48bbc6a898 | ||
|
0bfacb3d55 | ||
|
d85ed5f85f | ||
|
a64ed2bf72 | ||
|
f7137f42ad | ||
|
7bb798e40b | ||
|
09de5d162f | ||
|
385808c7a1 | ||
|
0d1396c815 | ||
|
a52b285f45 | ||
|
240867a432 | ||
|
c27e2997dd | ||
|
498844b4e7 | ||
|
93c151512f | ||
|
677c3ce6e8 | ||
|
fa443249c9 | ||
|
b2c2779465 | ||
|
029b3bdb80 | ||
|
8935160c72 | ||
|
fb8f74d2f0 | ||
|
e8e39fd862 | ||
|
736ec7da23 | ||
|
52084f4f1f | ||
|
cf0265ecf7 | ||
|
5e4c7de5c7 | ||
|
7bfd7ce0ca | ||
|
80a4d37173 | ||
|
615921108a | ||
|
7147649347 | ||
|
6f48ebe7fe | ||
|
ec595b9cff | ||
|
49beb7d7fd | ||
|
f8f16c44a9 | ||
|
6fb5277e95 | ||
|
a9a267290e | ||
|
6ae5b94df3 | ||
|
0d8dad878c | ||
|
da1f2f2ad3 | ||
|
cdefe52c67 | ||
|
1ecec68a20 | ||
|
df221e05be | ||
|
6f93872e0e | ||
|
46ce69a8a9 | ||
|
4d941545cd | ||
|
1316743b02 | ||
|
3eac35c158 | ||
|
c6191f4539 | ||
|
cc717f4112 | ||
|
b770800eda | ||
|
2e5a3606f3 | ||
|
43a534c98b | ||
|
1500e63050 | ||
|
b26aefd487 | ||
|
7c0858b3cb | ||
|
bfe4895408 | ||
|
5f547a9974 | ||
|
3d1d2ea334 | ||
|
a6b46a0ea0 | ||
|
87be5d43ea | ||
|
0fcea2738b | ||
|
98503a9fb7 | ||
|
ff287aee52 | ||
|
0a015b2843 | ||
|
5b627ae5cc | ||
|
ed70281766 | ||
|
fbcf8a1e0d | ||
|
99308e7044 | ||
|
cc6a56234c | ||
|
c199cfc8d7 | ||
|
77cde6ae4b | ||
|
d309842055 | ||
|
245961d5f9 | ||
|
d3f6af5c49 | ||
|
9c8756556a | ||
|
31e90bcdf4 | ||
|
5e76e11e6a | ||
|
4d7634da9e | ||
|
8a36358e94 | ||
|
fef6cd212b | ||
|
637e5e95f7 | ||
|
58621ca42b | ||
|
413ad23304 | ||
|
ddbbcf032a | ||
|
a6e9e0cfca | ||
|
054698a3ad | ||
|
42c36f5b84 | ||
|
0bbc958373 | ||
|
5fba93594d | ||
|
482b3a728c | ||
|
6bfd3e46e0 | ||
|
60b3386733 | ||
|
9321312fce | ||
|
95ede7a91d | ||
|
6e3a12b604 | ||
|
f7e6deeaf4 | ||
|
df791b057b | ||
|
ce6050b72a | ||
|
f8c3271e0c | ||
|
29b76243b9 | ||
|
95ae50478b | ||
|
77536dd68e | ||
|
2e63b42afa | ||
|
88ae1a26ff | ||
|
09fd6eeffc | ||
|
4b9bd1ec30 | ||
|
bd22c6e383 | ||
|
be0e1d9b12 | ||
|
358d41e277 | ||
|
5cb5be6923 | ||
|
40fd28f86c | ||
|
2144aa4f8f | ||
|
8b1ecae77f | ||
|
07859aba06 | ||
|
00cceaba75 | ||
|
b5d1e5aa80 | ||
|
9b72370399 | ||
|
001b8188e8 | ||
|
b1d6788292 | ||
|
732adf9063 | ||
|
bc5635269d | ||
|
b4165f9773 | ||
|
4c1cdeb19f | ||
|
12a1ae10b8 | ||
|
b92d2baa91 | ||
|
61fde22b41 | ||
|
efe95748b7 | ||
|
7b6089481c | ||
|
da367b373f | ||
|
348dc9a1ba | ||
|
eb9c6fb899 | ||
|
61337d5614 | ||
|
c39201cd8b | ||
|
4ab6466226 | ||
|
207d97bec0 | ||
|
fc476fd99e | ||
|
0a7f13ab5c | ||
|
f26c9443dc | ||
|
04a11f1343 | ||
|
d5b7baab75 | ||
|
0f4e45e39d | ||
|
1218a18bf4 | ||
|
65e0265fa0 | ||
|
4018f2c40f | ||
|
3529bd7664 | ||
|
0996a6a186 | ||
|
f3c732597b | ||
|
569f4adbac | ||
|
37037b6f8b | ||
|
959a7a202d | ||
|
1588248d14 | ||
|
54d21f9cd8 | ||
|
e96020e35c | ||
|
67ed8c5791 | ||
|
122de48368 | ||
|
75f0fc7807 | ||
|
7f892341e5 | ||
|
065e0fe462 | ||
|
33bfbe53af | ||
|
5fe8917bdc | ||
|
0b0c2aae93 | ||
|
b35d8dd8b2 | ||
|
a5715ae3e0 | ||
|
82e26aaca2 | ||
|
37276c081b | ||
|
955dba4498 | ||
|
cbab9e2efb | ||
|
ca0107ba54 | ||
|
7ef33e5901 | ||
|
05d1b8864c | ||
|
6fc1699d86 | ||
|
f948dd62a8 | ||
|
4b53f9f3a6 | ||
|
6ea36b5a27 | ||
|
ea64fd51ff | ||
|
6cd161a02d | ||
|
d85a18c24d | ||
|
904fcfe75a | ||
|
eff4644a00 | ||
|
4cbb4001fc | ||
|
b812cc19a9 | ||
|
2aec59dd23 | ||
|
1fc80182a3 | ||
|
a0e1e5f0c6 | ||
|
fdc21d3184 | ||
|
7064e12959 | ||
|
98195e606a | ||
|
f401597f10 | ||
|
7fae39b593 | ||
|
7449543461 | ||
|
3171da9e09 | ||
|
fc6758ffdf | ||
|
e2c28d9240 | ||
|
450db1657e | ||
|
f18d9ae831 | ||
|
c0eb7df97a | ||
|
374a43b27a | ||
|
3b266b9f05 | ||
|
24aa865ce2 | ||
|
6081ce6fa4 | ||
|
3c83f61637 | ||
|
f8484c0e1e | ||
|
661193fcb0 | ||
|
614ba62980 | ||
|
f865656991 | ||
|
3ff5d5d690 | ||
|
4b92233084 | ||
|
c3f98b388a | ||
|
049c366b78 | ||
|
f71067b024 | ||
|
431fd2de6f | ||
|
5f308c9f31 | ||
|
0af6c7d22a | ||
|
3b8e2a5528 | ||
|
b2ab26c727 | ||
|
5bcd60b3ba | ||
|
71674f8b7d | ||
|
243b2658e3 | ||
|
6dc35bcbad | ||
|
7b83b279d7 | ||
|
ca9f2717d5 | ||
|
76d6b04d53 | ||
|
c6de459c76 | ||
|
f5cb3589c9 | ||
|
d217e1ee9c | ||
|
29c3aff5e2 | ||
|
eb39afc68a | ||
|
4f5760af94 | ||
|
318bcff5b5 | ||
|
9b8d77891e | ||
|
9e57d01c99 | ||
|
8c78f105cc | ||
|
4f578a160f | ||
|
6f3fd21232 | ||
|
8420ed7b13 | ||
|
a29f0e8ccd | ||
|
405140cc8f |
60
.dockerignore
Normal file
60
.dockerignore
Normal file
@ -0,0 +1,60 @@
|
||||
# Docker build spec
|
||||
Dockerfile
|
||||
|
||||
# Git repository metadata
|
||||
.git
|
||||
**/.gitignore
|
||||
|
||||
# Object code
|
||||
**/*.o
|
||||
**/*.so
|
||||
**/*.lo
|
||||
**/*.la
|
||||
|
||||
# gcov files
|
||||
**/*.gcda
|
||||
**/*.gcov
|
||||
**/*.gcno
|
||||
|
||||
# Backup files
|
||||
**/*~
|
||||
|
||||
# Release files
|
||||
**/*.tar.gz
|
||||
|
||||
# Files currently being edited by vim or vi
|
||||
**/*.swp
|
||||
|
||||
# automake/autoconf
|
||||
**/.deps/
|
||||
**/.dirstamp
|
||||
**/.libs/
|
||||
**/Makefile
|
||||
**/Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
m4/*
|
||||
**/!README
|
||||
compile
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
test-driver
|
||||
|
||||
# Test binaries
|
||||
tests/test_*
|
||||
!tests/test_*.[ch]
|
||||
|
||||
# Generated docs
|
||||
doc/*/doxygen-output
|
||||
|
24
.gitignore
vendored
24
.gitignore
vendored
@ -10,6 +10,10 @@
|
||||
*.gcov
|
||||
*.gcno
|
||||
|
||||
# Test suite output
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
@ -23,32 +27,24 @@
|
||||
.deps/
|
||||
.dirstamp
|
||||
.libs/
|
||||
Doxyfile
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
build-aux/
|
||||
libtool
|
||||
m4/*
|
||||
!README
|
||||
compile
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
test-driver
|
||||
|
||||
# Test binaries
|
||||
tests/test_*
|
||||
!tests/test_*.[ch]
|
||||
|
||||
# Generated docs
|
||||
doc/doxygen-output
|
||||
doc/*/doxygen-output
|
||||
|
||||
# IDE metadata
|
||||
nbproject/
|
||||
|
10
AUTHORS
10
AUTHORS
@ -1,10 +0,0 @@
|
||||
Michael Jumper <mike.jumper@guac-dev.org>
|
||||
James Muehlner <james.muehlner@guac-dev.org>
|
||||
Matt Hortman <matt@FlintRiverSystems.com>
|
||||
Jocelyn Delalande <j.delalande@ulteo.com>
|
||||
David Lechevalier <david@ulteo.com>
|
||||
Alexandre Devely <alex@koumoula.com>
|
||||
Laurent Meunier <laurent@deltalima.net>
|
||||
Saul Gio Perez <gio.perez@sv.cmu.edu>
|
||||
Tom Sealy <tom.sealy@yahoo.com>
|
||||
Felipe Weckx <felipe@weckx.net>
|
52
CONTRIBUTING
Normal file
52
CONTRIBUTING
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
------------------------------------------------------------
|
||||
Contributing to Apache Guacamole
|
||||
------------------------------------------------------------
|
||||
|
||||
Thank you for contributing to the Apache Guacamole project!
|
||||
|
||||
There are certain procedures that must be followed for all contributions. These
|
||||
procedures are necessary to allow us to allocate resources for reviewing and
|
||||
testing your contribution, as well as communicate effectively with you during
|
||||
the review process.
|
||||
|
||||
1) Create an issue in our JIRA
|
||||
|
||||
All changes to Guacamole must have corresponding issues in JIRA so the
|
||||
change can be properly tracked:
|
||||
|
||||
https://issues.apache.org/jira/browse/GUACAMOLE/
|
||||
|
||||
If you do not already have an account on the Apache Software Foundation's
|
||||
JIRA, you will need to create one before creating your new issue.
|
||||
|
||||
2) Make and test your changes locally
|
||||
|
||||
The Guacamole source is maintained in git repositories hosted on GitHub:
|
||||
|
||||
https://github.com/apache/guacamole-client
|
||||
https://github.com/apache/guacamole-manual
|
||||
https://github.com/apache/guacamole-server
|
||||
https://github.com/apache/guacamole-website
|
||||
|
||||
To make your changes, fork the applicable repositories and make commits
|
||||
to a topic branch in your fork. Commits should be made in logical units
|
||||
and must reference the JIRA issue number:
|
||||
|
||||
$ git commit -m "GUACAMOLE-123: High-level message describing the changes."
|
||||
|
||||
Avoid commits which cover multiple, distinct goals that could (and should)
|
||||
be handled separately.
|
||||
|
||||
If you do not already have an account on GitHub, you will need to create
|
||||
one before making your changes.
|
||||
|
||||
3) Submit your changes via a pull request on GitHub
|
||||
|
||||
Once your changes are ready, submit them by creating a pull request for
|
||||
the corresponding topic branch you created when you began working on your
|
||||
changes.
|
||||
|
||||
The Guacamole team will then review your changes and, if they pass review,
|
||||
your changes will be merged.
|
||||
|
18
ChangeLog
18
ChangeLog
@ -1,18 +0,0 @@
|
||||
2013-08-26 Michael Jumper <mike.jumper@guac-dev.org>
|
||||
|
||||
* Experimental sound support for VNC (ticket #369)
|
||||
* Improved handling of frame flush (ticket #380)
|
||||
* SSL transport for guacd (ticket #371)
|
||||
* Fix segfault in RDP disconnect (ticket #385)
|
||||
* Add security options to RDP (ticket #190)
|
||||
|
||||
2013-07-02 Michael Jumper <mike.jumper@guac-dev.org>
|
||||
|
||||
* Optional threadsafety in guac_socket
|
||||
* Printing support in for RDP (ticket #110)
|
||||
* Fix ENABLE_OGG bug (ticket #355)
|
||||
|
||||
2013-06-06 Michael Jumper <mike.jumper@guac-dev.org>
|
||||
|
||||
* Created new repository layout
|
||||
|
201
Dockerfile
Normal file
201
Dockerfile
Normal file
@ -0,0 +1,201 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# Dockerfile for guacamole-server
|
||||
#
|
||||
|
||||
# The Alpine Linux image that should be used as the basis for the guacd image
|
||||
ARG ALPINE_BASE_IMAGE=latest
|
||||
FROM alpine:${ALPINE_BASE_IMAGE} AS builder
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache \
|
||||
autoconf \
|
||||
automake \
|
||||
build-base \
|
||||
cairo-dev \
|
||||
cmake \
|
||||
git \
|
||||
grep \
|
||||
libjpeg-turbo-dev \
|
||||
libpng-dev \
|
||||
libtool \
|
||||
libwebp-dev \
|
||||
make \
|
||||
openssl-dev \
|
||||
pango-dev \
|
||||
pulseaudio-dev \
|
||||
util-linux-dev
|
||||
|
||||
# Copy source to container for sake of build
|
||||
ARG BUILD_DIR=/tmp/guacamole-server
|
||||
COPY . ${BUILD_DIR}
|
||||
|
||||
#
|
||||
# Base directory for installed build artifacts.
|
||||
#
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the second stage of the build.
|
||||
#
|
||||
ARG PREFIX_DIR=/opt/guacamole
|
||||
|
||||
#
|
||||
# Automatically select the latest versions of each core protocol support
|
||||
# library (these can be overridden at build time if a specific version is
|
||||
# needed)
|
||||
#
|
||||
ARG WITH_FREERDP='2(\.\d+)+'
|
||||
ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
|
||||
ARG WITH_LIBTELNET='\d+(\.\d+)+'
|
||||
ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
|
||||
ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
|
||||
|
||||
#
|
||||
# Default build options for each core protocol support library, as well as
|
||||
# guacamole-server itself (these can be overridden at build time if different
|
||||
# options are needed)
|
||||
#
|
||||
|
||||
ARG FREERDP_OPTS="\
|
||||
-DBUILTIN_CHANNELS=OFF \
|
||||
-DCHANNEL_URBDRC=OFF \
|
||||
-DWITH_ALSA=OFF \
|
||||
-DWITH_CAIRO=ON \
|
||||
-DWITH_CHANNELS=ON \
|
||||
-DWITH_CLIENT=ON \
|
||||
-DWITH_CUPS=OFF \
|
||||
-DWITH_DIRECTFB=OFF \
|
||||
-DWITH_FFMPEG=OFF \
|
||||
-DWITH_GSM=OFF \
|
||||
-DWITH_GSSAPI=OFF \
|
||||
-DWITH_IPP=OFF \
|
||||
-DWITH_JPEG=ON \
|
||||
-DWITH_LIBSYSTEMD=OFF \
|
||||
-DWITH_MANPAGES=OFF \
|
||||
-DWITH_OPENH264=OFF \
|
||||
-DWITH_OPENSSL=ON \
|
||||
-DWITH_OSS=OFF \
|
||||
-DWITH_PCSC=OFF \
|
||||
-DWITH_PULSE=OFF \
|
||||
-DWITH_SERVER=OFF \
|
||||
-DWITH_SERVER_INTERFACE=OFF \
|
||||
-DWITH_SHADOW_MAC=OFF \
|
||||
-DWITH_SHADOW_X11=OFF \
|
||||
-DWITH_SSE2=ON \
|
||||
-DWITH_WAYLAND=OFF \
|
||||
-DWITH_X11=OFF \
|
||||
-DWITH_X264=OFF \
|
||||
-DWITH_XCURSOR=ON \
|
||||
-DWITH_XEXT=ON \
|
||||
-DWITH_XI=OFF \
|
||||
-DWITH_XINERAMA=OFF \
|
||||
-DWITH_XKBFILE=ON \
|
||||
-DWITH_XRENDER=OFF \
|
||||
-DWITH_XTEST=OFF \
|
||||
-DWITH_XV=OFF \
|
||||
-DWITH_ZLIB=ON"
|
||||
|
||||
ARG GUACAMOLE_SERVER_OPTS="\
|
||||
--disable-guaclog"
|
||||
|
||||
ARG LIBSSH2_OPTS="\
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DBUILD_SHARED_LIBS=ON"
|
||||
|
||||
ARG LIBTELNET_OPTS="\
|
||||
--disable-static \
|
||||
--disable-util"
|
||||
|
||||
ARG LIBVNCCLIENT_OPTS=""
|
||||
|
||||
ARG LIBWEBSOCKETS_OPTS="\
|
||||
-DDISABLE_WERROR=ON \
|
||||
-DLWS_WITHOUT_SERVER=ON \
|
||||
-DLWS_WITHOUT_TESTAPPS=ON \
|
||||
-DLWS_WITHOUT_TEST_CLIENT=ON \
|
||||
-DLWS_WITHOUT_TEST_PING=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER=ON \
|
||||
-DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \
|
||||
-DLWS_WITH_STATIC=OFF"
|
||||
|
||||
# Build guacamole-server and its core protocol library dependencies
|
||||
RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
|
||||
|
||||
# Record the packages of all runtime library dependencies
|
||||
RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
|
||||
${PREFIX_DIR}/sbin/guacd \
|
||||
${PREFIX_DIR}/lib/libguac-client-*.so \
|
||||
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
|
||||
> ${PREFIX_DIR}/DEPENDENCIES
|
||||
|
||||
# Use same Alpine version as the base for the runtime image
|
||||
FROM alpine:${ALPINE_BASE_IMAGE}
|
||||
|
||||
#
|
||||
# Base directory for installed build artifacts. See also the
|
||||
# CMD directive at the end of this build stage.
|
||||
#
|
||||
# NOTE: Due to limitations of the Docker image build process, this value is
|
||||
# duplicated in an ARG in the first stage of the build.
|
||||
#
|
||||
ARG PREFIX_DIR=/opt/guacamole
|
||||
|
||||
# Runtime environment
|
||||
ENV LC_ALL=C.UTF-8
|
||||
ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
|
||||
ENV GUACD_LOG_LEVEL=info
|
||||
|
||||
# Copy build artifacts into this stage
|
||||
COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
|
||||
|
||||
# Bring runtime environment up to date and install runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
ghostscript \
|
||||
netcat-openbsd \
|
||||
shadow \
|
||||
terminus-font \
|
||||
ttf-dejavu \
|
||||
ttf-liberation \
|
||||
util-linux-login && \
|
||||
xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES
|
||||
|
||||
# Checks the operating status every 5 minutes with a timeout of 5 seconds
|
||||
HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
|
||||
|
||||
# Create a new user guacd
|
||||
ARG UID=1000
|
||||
ARG GID=1000
|
||||
RUN groupadd --gid $GID guacd
|
||||
RUN useradd --system --create-home --shell /sbin/nologin --uid $UID --gid $GID guacd
|
||||
|
||||
# Run with user guacd
|
||||
USER guacd
|
||||
|
||||
# Expose the default listener port
|
||||
EXPOSE 4822
|
||||
|
||||
# Start guacd, listening on port 0.0.0.0:4822
|
||||
#
|
||||
# Note the path here MUST correspond to the value specified in the
|
||||
# PREFIX_DIR build argument.
|
||||
#
|
||||
CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f
|
||||
|
215
LICENSE
215
LICENSE
@ -1,19 +1,202 @@
|
||||
Copyright (C) 2013 Glyptodon LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
113
Makefile.am
113
Makefile.am
@ -1,64 +1,103 @@
|
||||
#
|
||||
# Copyright (C) 2013 Glyptodon LLC
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Subprojects
|
||||
DIST_SUBDIRS = \
|
||||
src/libguac \
|
||||
src/common \
|
||||
src/terminal \
|
||||
src/guacd \
|
||||
src/protocols/rdp \
|
||||
src/protocols/ssh \
|
||||
src/protocols/telnet \
|
||||
src/protocols/vnc \
|
||||
tests
|
||||
DIST_SUBDIRS = \
|
||||
src/libguac \
|
||||
src/common \
|
||||
src/common-ssh \
|
||||
src/terminal \
|
||||
src/guacd \
|
||||
src/guacenc \
|
||||
src/guaclog \
|
||||
src/pulse \
|
||||
src/protocols/kubernetes \
|
||||
src/protocols/rdp \
|
||||
src/protocols/ssh \
|
||||
src/protocols/telnet \
|
||||
src/protocols/vnc
|
||||
|
||||
SUBDIRS = \
|
||||
src/libguac \
|
||||
src/common \
|
||||
src/guacd \
|
||||
tests
|
||||
SUBDIRS = \
|
||||
src/libguac \
|
||||
src/common
|
||||
|
||||
if ENABLE_COMMON_SSH
|
||||
SUBDIRS += src/common-ssh
|
||||
endif
|
||||
|
||||
if ENABLE_TERMINAL
|
||||
SUBDIRS += src/terminal
|
||||
SUBDIRS += src/terminal
|
||||
endif
|
||||
|
||||
if ENABLE_PULSE
|
||||
SUBDIRS += src/pulse
|
||||
endif
|
||||
|
||||
if ENABLE_KUBERNETES
|
||||
SUBDIRS += src/protocols/kubernetes
|
||||
endif
|
||||
|
||||
if ENABLE_RDP
|
||||
SUBDIRS += src/protocols/rdp
|
||||
SUBDIRS += src/protocols/rdp
|
||||
endif
|
||||
|
||||
if ENABLE_SSH
|
||||
SUBDIRS += src/protocols/ssh
|
||||
SUBDIRS += src/protocols/ssh
|
||||
endif
|
||||
|
||||
if ENABLE_TELNET
|
||||
SUBDIRS += src/protocols/telnet
|
||||
SUBDIRS += src/protocols/telnet
|
||||
endif
|
||||
|
||||
if ENABLE_VNC
|
||||
SUBDIRS += src/protocols/vnc
|
||||
SUBDIRS += src/protocols/vnc
|
||||
endif
|
||||
|
||||
EXTRA_DIST = LICENSE doc/Doxyfile bin/guacctl
|
||||
if ENABLE_GUACD
|
||||
SUBDIRS += src/guacd
|
||||
endif
|
||||
|
||||
if ENABLE_GUACENC
|
||||
SUBDIRS += src/guacenc
|
||||
endif
|
||||
|
||||
if ENABLE_GUACLOG
|
||||
SUBDIRS += src/guaclog
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
.dockerignore \
|
||||
CONTRIBUTING \
|
||||
Dockerfile \
|
||||
LICENSE \
|
||||
NOTICE \
|
||||
bin/guacctl \
|
||||
doc/libguac/Doxyfile.in \
|
||||
doc/libguac-terminal/Doxyfile.in \
|
||||
src/guacd-docker \
|
||||
util/generate-test-runner.pl
|
||||
|
||||
|
5
NOTICE
Normal file
5
NOTICE
Normal file
@ -0,0 +1,5 @@
|
||||
Apache Guacamole
|
||||
Copyright 2020 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
94
README
94
README
@ -4,16 +4,15 @@
|
||||
------------------------------------------------------------
|
||||
|
||||
This README is intended to provide quick and to-the-point documentation for
|
||||
technical users intending to compile parts of Guacamole themselves.
|
||||
technical users intending to compile parts of Apache Guacamole themselves.
|
||||
|
||||
Distribution-specific packages are available from the files section of the main
|
||||
project page:
|
||||
Source archives are available from the downloads section of the project website:
|
||||
|
||||
http://sourceforge.net/projects/guacamole/files/
|
||||
http://guacamole.apache.org/
|
||||
|
||||
Distribution-specific documentation is provided on the Guacamole wiki:
|
||||
A full manual is available as well:
|
||||
|
||||
http://guac-dev.org/
|
||||
http://guacamole.apache.org/doc/gug/
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
@ -26,25 +25,75 @@ libraries.
|
||||
|
||||
guacd is the Guacamole proxy daemon used by the Guacamole web application and
|
||||
framework. As JavaScript cannot handle binary protocols (like VNC and remote
|
||||
desktop) efficiently, a new test-based protocol was developed which would
|
||||
desktop) efficiently, a new text-based protocol was developed which would
|
||||
contain a common superset of the operations needed for efficient remote desktop
|
||||
access, but would be easy for JavaScript programs to process. guacd is the
|
||||
proxy which translates between arbitrary protocols and the Guacamole protocol.
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
Required dependencies
|
||||
------------------------------------------------------------
|
||||
|
||||
All software within guacamole-server is built using the popular GNU Automake,
|
||||
and thus provides the standard configure script. Before compiling, at least
|
||||
the following required dependencies must already be installed:
|
||||
|
||||
1) Cairo (http://cairographics.org/)
|
||||
|
||||
2) libjpeg-turbo (http://libjpeg-turbo.virtualgl.org/)
|
||||
OR libjpeg (http://www.ijg.org/)
|
||||
|
||||
3) libpng (http://www.libpng.org/pub/png/libpng.html)
|
||||
|
||||
4) OSSP UUID (http://www.ossp.org/pkg/lib/uuid/)
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
Optional dependencies
|
||||
------------------------------------------------------------
|
||||
|
||||
In addition, the following optional dependencies may be installed in order to
|
||||
enable optional features of Guacamole. Note that while the various supported
|
||||
protocols are technically optional, you will no doubt wish to install the
|
||||
dependencies of at least ONE supported protocol, as Guacamole would be useless
|
||||
otherwise.
|
||||
|
||||
RDP:
|
||||
* FreeRDP (http://www.freerdp.com/)
|
||||
|
||||
SSH:
|
||||
* libssh2 (http://www.libssh2.org/)
|
||||
* OpenSSL (https://www.openssl.org/)
|
||||
* Pango (http://www.pango.org/)
|
||||
|
||||
Telnet:
|
||||
* libtelnet (https://github.com/seanmiddleditch/libtelnet)
|
||||
* Pango (http://www.pango.org/)
|
||||
|
||||
VNC:
|
||||
* libVNCserver (http://libvnc.github.io/)
|
||||
|
||||
Support for audio within VNC:
|
||||
* PulseAudio (http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||
|
||||
Support for SFTP file transfer for VNC or RDP:
|
||||
* libssh2 (http://www.libssh2.org/)
|
||||
* OpenSSL (https://www.openssl.org/)
|
||||
|
||||
Support for WebP image compression:
|
||||
* libwebp (https://developers.google.com/speed/webp/)
|
||||
|
||||
"guacenc" video encoding utility:
|
||||
* FFmpeg (https://ffmpeg.org/)
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
Compiling and installing guacd, libguac, etc.
|
||||
------------------------------------------------------------
|
||||
|
||||
Please note that distribution-specific pre-compiled packages are available from
|
||||
the files section of the main project site:
|
||||
|
||||
http://sourceforge.net/projects/guacamole/files/
|
||||
|
||||
All software within guacamole-server is built using the popular GNU Automake,
|
||||
and thus provides the standard configure script. Before compiling, you need to
|
||||
have compiled and installed libguac, the core Guacamole library. This is
|
||||
available from the main Guacamole site at http://guac-dev.org/.
|
||||
and thus provides the standard configure script.
|
||||
|
||||
1) Run configure
|
||||
|
||||
@ -95,7 +144,7 @@ guacd itself directly without the init script (as any user):
|
||||
|
||||
$ guacd
|
||||
|
||||
guacd currently takes four command-line options:
|
||||
guacd currently takes several command-line options:
|
||||
|
||||
-b HOST
|
||||
|
||||
@ -111,17 +160,26 @@ guacd currently takes four command-line options:
|
||||
file. This is useful for init scripts and is used by the provided init
|
||||
script.
|
||||
|
||||
-L LEVEL
|
||||
|
||||
Sets the maximum level at which guacd will log messages to syslog and,
|
||||
if running in the foreground, the console. Legal values are debug,
|
||||
info, warning, and error. The default value is info.
|
||||
|
||||
-f
|
||||
Causes guacd to run in the foreground, rather than automatically
|
||||
forking into the background.
|
||||
|
||||
Additional information can be found in the guacd man page:
|
||||
|
||||
$ man guacd
|
||||
|
||||
------------------------------------------------------------
|
||||
Reporting problems
|
||||
------------------------------------------------------------
|
||||
|
||||
Please report any bugs encountered by opening a new ticket at the Trac system
|
||||
Please report any bugs encountered by opening a new issue in the JIRA system
|
||||
hosted at:
|
||||
|
||||
http://guac-dev.rg/trac/
|
||||
https://issues.apache.org/jira/browse/GUACAMOLE
|
||||
|
||||
|
89
README-unit-testing.md
Normal file
89
README-unit-testing.md
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
Unit testing and guacamole-server
|
||||
=================================
|
||||
|
||||
Unit tests within guacamole-server are implemented using the following:
|
||||
|
||||
* automake, which allows arbitrary tests to be declared within `Makefile.am`
|
||||
and uses `make check` to run those tests.
|
||||
* CUnit (libcunit), a unit testing framework.
|
||||
* `util/generate-test-runner.pl`, a Perl script which generates a test runner
|
||||
written in C which leverages CUnit, running the unit tests declared in each
|
||||
of the given `.c` files. The generated test runner produces output in [TAP
|
||||
format](https://testanything.org/) which is consumed by the TAP test driver
|
||||
provided by automake.
|
||||
|
||||
Writing unit tests
|
||||
------------------
|
||||
|
||||
All unit tests should be within reasonably-isolated C source files, with each
|
||||
logical test having its own function of the form:
|
||||
|
||||
void test_SUITENAME__TESTNAME() {
|
||||
...
|
||||
}
|
||||
|
||||
where `TESTNAME` is the arbitrary name of the test and `SUITENAME` is the
|
||||
arbitrary name of the test suite that this test belongs to.
|
||||
|
||||
**This naming convention is required by `generate-test-runner.pl`.** Absolutely
|
||||
all tests MUST follow the above convention if they are to be picked up and
|
||||
organized by the test runner generation script. Functions which are not tests
|
||||
MUST NOT follow the above convention so that they are _not_ picked up mistakenly
|
||||
by the test runner generator as if they were tests.
|
||||
|
||||
The `Makefile.am` for a subproject which contains such tests is typically
|
||||
modified to contain a sections like the following:
|
||||
|
||||
#
|
||||
# Unit tests for myproj
|
||||
#
|
||||
|
||||
check_PROGRAMS = test_myproj
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
test_myproj_SOURCES = \
|
||||
...all source files...
|
||||
|
||||
test_myproj_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
...other flags...
|
||||
|
||||
test_myproj_LDADD = \
|
||||
...libraries...
|
||||
|
||||
#
|
||||
# Autogenerate test runner
|
||||
#
|
||||
|
||||
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_myproj_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_myproj_SOURCES) > $@
|
||||
|
||||
nodist_test_libguac_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
||||
# Use automake's TAP test driver for running any tests
|
||||
LOG_DRIVER = \
|
||||
env AM_TAP_AWK='$(AWK)' \
|
||||
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
|
||||
|
||||
The above declares ...
|
||||
|
||||
* ... that a binary, `test_myproj` should be built from the given sources.
|
||||
Note that `test_myproj_SOURCES` contains only the source which was actually
|
||||
written by hand while `nodist_test_myproj_SOURCES` contains only the source
|
||||
which was generated by `generate-test-runner.pl`.
|
||||
* ... that this `test_myproj` binary should be run to test this project when
|
||||
`make check` is run, and that automake's TAP driver should be used to
|
||||
consume its output.
|
||||
* ... that the `_generated_runner.c` source file is generated dynamically
|
||||
(through running `generate-test-runner.pl` on all non-generated test source)
|
||||
and should not be distributed as part of the source archive.
|
||||
|
||||
With tests following the above naming convention in place, and with the
|
||||
necessary changes made to the applicable `Makefile.am`, all tests will be
|
||||
run automatically when `make check` is run.
|
||||
|
316
bin/guacctl
316
bin/guacctl
@ -1,44 +1,46 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2013 Glyptodon LLC
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# guacctl
|
||||
# -------
|
||||
#
|
||||
# Utility for sending Guacamole-specific console codes for controlling the SSH
|
||||
# session, such as:
|
||||
# Utility for sending Guacamole-specific console codes for controlling a
|
||||
# terminal session, such as:
|
||||
#
|
||||
# * Downloading files
|
||||
# * Setting the destination directory for uploads
|
||||
# * Downloading files (SSH only)
|
||||
# * Setting the destination directory for uploads (SSH only)
|
||||
# * Redirecting output to a named pipe stream (SSH or telnet)
|
||||
#
|
||||
# This script may also be run as "guacget", in which case the script accepts
|
||||
# no options and assumes anything given on the commandline is a file to be
|
||||
# downloaded.
|
||||
#
|
||||
|
||||
|
||||
# Given the name of a file, which may be a relative path, produce the full,
|
||||
# real, non-relative path for that same file.
|
||||
##
|
||||
## Given the name of a file, which may be a relative path, produce the full,
|
||||
## real, non-relative path for that same file.
|
||||
##
|
||||
## @param FILENAME
|
||||
## The name of the file to produce the full path of.
|
||||
##
|
||||
fullpath() {
|
||||
FILENAME="$1"
|
||||
DIR=`dirname "$FILENAME"`
|
||||
@ -46,44 +48,112 @@ fullpath() {
|
||||
(cd "$DIR" && echo "$PWD/$FILE")
|
||||
}
|
||||
|
||||
# Sends the Guacamole-specific console code for initiating a download.
|
||||
##
|
||||
## Sends the Guacamole-specific console code for initiating a download.
|
||||
##
|
||||
## @param FILENAME
|
||||
## The full path of the file to download.
|
||||
##
|
||||
send_download_file() {
|
||||
FILENAME="$1"
|
||||
printf "\033]482200;%s\007" "$FILENAME"
|
||||
}
|
||||
|
||||
# Sends the Guacamole-specific console code for setting the upload directory.
|
||||
##
|
||||
## Sends the Guacamole-specific console code for setting the upload directory.
|
||||
##
|
||||
## @param FILENAME
|
||||
## The full path to the directory which should receive uploads.
|
||||
##
|
||||
send_set_directory() {
|
||||
FILENAME="$1"
|
||||
printf "\033]482201;%s\007" "$FILENAME"
|
||||
}
|
||||
|
||||
# Prints the given error text to STDERR.
|
||||
##
|
||||
## Sends the Guacamole-specific console code for redirecting output to a named
|
||||
## pipe stream (instead of the terminal emulator)
|
||||
##
|
||||
## @param NAME
|
||||
## The name of the pipe stream to open.
|
||||
##
|
||||
send_open_pipe_stream() {
|
||||
NAME="$1"
|
||||
printf "\033]482202;%s\007" "$NAME"
|
||||
}
|
||||
|
||||
##
|
||||
## Sends the Guacamole-specific console code for redirecting output back to the
|
||||
## terminal emulator
|
||||
##
|
||||
send_close_pipe_stream() {
|
||||
printf "\033]482203;\007"
|
||||
}
|
||||
|
||||
##
|
||||
## Sends the Guacamole-specific console code for resizing the scrollback
|
||||
## buffer.
|
||||
##
|
||||
## @param ROWS
|
||||
## The number of rows that the scrollback buffer should contain.
|
||||
##
|
||||
send_resize_scrollback() {
|
||||
ROWS="$1"
|
||||
printf "\033]482204;%s\007" "$ROWS"
|
||||
}
|
||||
|
||||
##
|
||||
## Prints the given error text to STDERR.
|
||||
##
|
||||
## @param ...
|
||||
## The text to print as an error message.
|
||||
##
|
||||
error() {
|
||||
echo "$NAME:" "$@" >&2
|
||||
}
|
||||
|
||||
# Prints usage documentation for this script.
|
||||
##
|
||||
## Prints usage documentation for this script.
|
||||
##
|
||||
usage() {
|
||||
cat >&2 <<END
|
||||
guacctl 0.8.0, Guacamole SSH session control utility.
|
||||
Usage: guacctl [OPTION] [FILE]...
|
||||
guacctl 1.5.0, Apache Guacamole terminal session control utility.
|
||||
Usage: guacctl [OPTION] [FILE or NAME]...
|
||||
|
||||
-d, --download download each of the files listed.
|
||||
-s, --set-directory set the destination directory for future uploaded
|
||||
files.
|
||||
-o, --open-pipe redirect output to a new pipe stream with the given
|
||||
name.
|
||||
-c, --close-pipe close any existing pipe stream and redirect output
|
||||
back to the terminal emulator.
|
||||
-S, --scrollback request that the scrollback buffer be limited to the
|
||||
given number of rows.
|
||||
END
|
||||
}
|
||||
|
||||
# Initiates a download for each of the specified files
|
||||
##
|
||||
## Initiates a download for each of the specified files.
|
||||
##
|
||||
## @param ...
|
||||
## The name of each file that should be downloaded, as originally
|
||||
## provided to guacctl.
|
||||
##
|
||||
download_files() {
|
||||
|
||||
#
|
||||
# Validate arguments
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
error "No files specified."
|
||||
return;
|
||||
fi
|
||||
|
||||
#
|
||||
# Send download code for each file given
|
||||
#
|
||||
|
||||
for FILENAME in "$@"; do
|
||||
if [ -e "$FILENAME" ]; then
|
||||
send_download_file "`fullpath "$FILENAME"`"
|
||||
@ -94,10 +164,18 @@ download_files() {
|
||||
|
||||
}
|
||||
|
||||
# Changes the upload path for future uploads to the given directory
|
||||
##
|
||||
## Changes the upload path for future uploads to the given directory.
|
||||
##
|
||||
## @param ...
|
||||
## The name of the directory to use for uploads, as provided to guacctl.
|
||||
##
|
||||
set_directory() {
|
||||
|
||||
#
|
||||
# Validate arguments
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
error "No destination directory specified."
|
||||
return;
|
||||
@ -108,6 +186,10 @@ set_directory() {
|
||||
return;
|
||||
fi
|
||||
|
||||
#
|
||||
# Send code for setting the upload directory
|
||||
#
|
||||
|
||||
FILENAME="$1"
|
||||
if [ -d "$FILENAME" ]; then
|
||||
send_set_directory "`fullpath "$FILENAME"`"
|
||||
@ -117,20 +199,170 @@ set_directory() {
|
||||
|
||||
}
|
||||
|
||||
##
|
||||
## Opens a new pipe stream having the given name and redirects terminal output
|
||||
## to that stream.
|
||||
##
|
||||
## @param ...
|
||||
## The name of the pipe stream to open, as provided to guacctl.
|
||||
##
|
||||
open_pipe_stream() {
|
||||
|
||||
#
|
||||
# Validate arguments
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
error "No pipe name specified."
|
||||
return;
|
||||
fi
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
error "Only one pipe name may be given."
|
||||
return;
|
||||
fi
|
||||
|
||||
#
|
||||
# Send code for opening the named pipe stream
|
||||
#
|
||||
|
||||
NAME="$1"
|
||||
send_open_pipe_stream "$NAME"
|
||||
|
||||
}
|
||||
|
||||
##
|
||||
## Closes the currently-open pipe stream and redirects terminal output back to
|
||||
## the terminal emulator
|
||||
##
|
||||
## @param ...
|
||||
## The arguments provided to guacctl, which should be empty.
|
||||
##
|
||||
close_pipe_stream() {
|
||||
|
||||
#
|
||||
# Validate arguments
|
||||
#
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
error "Closing an open pipe stream does not require any arguments."
|
||||
return;
|
||||
fi
|
||||
|
||||
#
|
||||
# Send code for closing the currently-open named pipe stream
|
||||
#
|
||||
|
||||
send_close_pipe_stream
|
||||
|
||||
}
|
||||
|
||||
##
|
||||
## Resizes the scrollback buffer to the given number of rows.
|
||||
##
|
||||
## @param ...
|
||||
## The number of rows that should be contained within the scrollback
|
||||
## buffer, as provided to guacctl.
|
||||
##
|
||||
resize_scrollback() {
|
||||
|
||||
#
|
||||
# Validate arguments
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
error "No row count specified."
|
||||
return;
|
||||
fi
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
error "Only one row count may be given."
|
||||
return;
|
||||
fi
|
||||
|
||||
#
|
||||
# Send code for resizing scrollback
|
||||
#
|
||||
|
||||
ROWS="$1"
|
||||
send_resize_scrollback "$ROWS"
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Get script name
|
||||
#
|
||||
|
||||
NAME=`basename "$0"`
|
||||
|
||||
# Parse options
|
||||
#
|
||||
# Handle downloads directly if invoked as "guacget"
|
||||
#
|
||||
|
||||
if [ "x$NAME" = "xguacget" ]; then
|
||||
download_files "$@"
|
||||
elif [ "x$1" = "x--download" -o "x$1" = "x-d" ]; then
|
||||
shift
|
||||
download_files "$@"
|
||||
elif [ "x$1" = "x--set-directory" -o "x$1" = "x-s" ]; then
|
||||
shift
|
||||
set_directory "$@"
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
#
|
||||
# Parse options
|
||||
#
|
||||
|
||||
case "$1" in
|
||||
|
||||
#
|
||||
# Download files
|
||||
#
|
||||
|
||||
"--download"|"-d")
|
||||
shift
|
||||
download_files "$@"
|
||||
;;
|
||||
|
||||
#
|
||||
# Set upload directory
|
||||
#
|
||||
|
||||
"--set-directory"|"-s")
|
||||
shift
|
||||
set_directory "$@"
|
||||
;;
|
||||
|
||||
#
|
||||
# Redirect to pipe
|
||||
#
|
||||
|
||||
"--open-pipe"|"-o")
|
||||
shift
|
||||
open_pipe_stream "$@"
|
||||
;;
|
||||
|
||||
#
|
||||
# Redirect back to terminal
|
||||
#
|
||||
|
||||
"--close-pipe"|"-c")
|
||||
shift
|
||||
close_pipe_stream "$@"
|
||||
;;
|
||||
|
||||
#
|
||||
# Resize scrollback
|
||||
#
|
||||
|
||||
"--scrollback"|"-S")
|
||||
shift
|
||||
resize_scrollback "$@"
|
||||
;;
|
||||
|
||||
#
|
||||
# Show usage info if options are invalid
|
||||
#
|
||||
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
1315
configure.ac
1315
configure.ac
File diff suppressed because it is too large
Load Diff
1551
doc/Doxyfile
1551
doc/Doxyfile
File diff suppressed because it is too large
Load Diff
58
doc/libguac-terminal/Doxyfile.in
Normal file
58
doc/libguac-terminal/Doxyfile.in
Normal file
@ -0,0 +1,58 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# Project name / version
|
||||
#
|
||||
|
||||
PROJECT_NAME = libguac-terminal
|
||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
|
||||
#
|
||||
# Warn about undocumented parameters and return values, but do not fill output
|
||||
# with verbose progress info.
|
||||
#
|
||||
|
||||
QUIET = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
#
|
||||
# Output format
|
||||
#
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_LATEX = NO
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OUTPUT_DIRECTORY = doxygen-output
|
||||
RECURSIVE = YES
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
|
||||
#
|
||||
# Input format
|
||||
#
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
FILE_PATTERNS = *.h
|
||||
STRIP_FROM_PATH = ../../src/terminal
|
||||
INPUT = ../../src/terminal/terminal/terminal.h
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
TAB_SIZE = 4
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
|
60
doc/libguac/Doxyfile.in
Normal file
60
doc/libguac/Doxyfile.in
Normal file
@ -0,0 +1,60 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# Project name / version
|
||||
#
|
||||
|
||||
PROJECT_NAME = libguac
|
||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
|
||||
#
|
||||
# Warn about undocumented parameters and return values, but do not fill output
|
||||
# with verbose progress info.
|
||||
#
|
||||
|
||||
QUIET = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
#
|
||||
# Output format
|
||||
#
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_LATEX = NO
|
||||
IGNORE_PREFIX = guac_ vguac_
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OUTPUT_DIRECTORY = doxygen-output
|
||||
RECURSIVE = YES
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
|
||||
#
|
||||
# Input format
|
||||
#
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
EXCLUDE_SYMBOLS = __* guac_palette*
|
||||
FILE_PATTERNS = *.h
|
||||
INPUT = ../../src/libguac/guacamole
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
STRIP_FROM_PATH = ../../src/libguac
|
||||
TAB_SIZE = 4
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
|
5
src/common-ssh/.gitignore
vendored
Normal file
5
src/common-ssh/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# Auto-generated test runner and binary
|
||||
_generated_runner.c
|
||||
test_common_ssh
|
||||
|
58
src/common-ssh/Makefile.am
Normal file
58
src/common-ssh/Makefile.am
Normal file
@ -0,0 +1,58 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
noinst_LTLIBRARIES = libguac_common_ssh.la
|
||||
SUBDIRS = . tests
|
||||
|
||||
libguac_common_ssh_la_SOURCES = \
|
||||
buffer.c \
|
||||
sftp.c \
|
||||
ssh.c \
|
||||
key.c \
|
||||
user.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
common-ssh/buffer.h \
|
||||
common-ssh/key.h \
|
||||
common-ssh/sftp.h \
|
||||
common-ssh/ssh.h \
|
||||
common-ssh/user.h
|
||||
|
||||
libguac_common_ssh_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@COMMON_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
libguac_common_ssh_la_LIBADD = \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
libguac_common_ssh_la_LDFLAGS = \
|
||||
@PTHREAD_LIBS@ \
|
||||
@SSH_LIBS@ \
|
||||
@SSL_LIBS@
|
||||
|
135
src/common-ssh/buffer.c
Normal file
135
src/common-ssh/buffer.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void guac_common_ssh_buffer_write_byte(char** buffer, uint8_t value) {
|
||||
|
||||
uint8_t* data = (uint8_t*) *buffer;
|
||||
*data = value;
|
||||
|
||||
(*buffer)++;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_buffer_write_uint32(char** buffer, uint32_t value) {
|
||||
|
||||
uint8_t* data = (uint8_t*) *buffer;
|
||||
|
||||
data[0] = (value & 0xFF000000) >> 24;
|
||||
data[1] = (value & 0x00FF0000) >> 16;
|
||||
data[2] = (value & 0x0000FF00) >> 8;
|
||||
data[3] = value & 0x000000FF;
|
||||
|
||||
*buffer += 4;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_buffer_write_data(char** buffer, const char* data,
|
||||
int length) {
|
||||
memcpy(*buffer, data, length);
|
||||
*buffer += length;
|
||||
}
|
||||
|
||||
void guac_common_ssh_buffer_write_bignum(char** buffer, const BIGNUM* value) {
|
||||
|
||||
unsigned char* bn_buffer;
|
||||
int length;
|
||||
|
||||
/* If zero, just write zero length */
|
||||
if (BN_is_zero(value)) {
|
||||
guac_common_ssh_buffer_write_uint32(buffer, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate output buffer, add padding byte */
|
||||
length = BN_num_bytes(value);
|
||||
bn_buffer = malloc(length);
|
||||
|
||||
/* Convert BIGNUM */
|
||||
BN_bn2bin(value, bn_buffer);
|
||||
|
||||
/* If first byte has high bit set, write padding byte */
|
||||
if (bn_buffer[0] & 0x80) {
|
||||
guac_common_ssh_buffer_write_uint32(buffer, length+1);
|
||||
guac_common_ssh_buffer_write_byte(buffer, 0);
|
||||
}
|
||||
else
|
||||
guac_common_ssh_buffer_write_uint32(buffer, length);
|
||||
|
||||
/* Write data */
|
||||
memcpy(*buffer, bn_buffer, length);
|
||||
*buffer += length;
|
||||
|
||||
free(bn_buffer);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_buffer_write_string(char** buffer, const char* string,
|
||||
int length) {
|
||||
guac_common_ssh_buffer_write_uint32(buffer, length);
|
||||
guac_common_ssh_buffer_write_data(buffer, string, length);
|
||||
}
|
||||
|
||||
uint8_t guac_common_ssh_buffer_read_byte(char** buffer) {
|
||||
|
||||
uint8_t* data = (uint8_t*) *buffer;
|
||||
uint8_t value = *data;
|
||||
|
||||
(*buffer)++;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
uint32_t guac_common_ssh_buffer_read_uint32(char** buffer) {
|
||||
|
||||
uint8_t* data = (uint8_t*) *buffer;
|
||||
uint32_t value =
|
||||
(data[0] << 24)
|
||||
| (data[1] << 16)
|
||||
| (data[2] << 8)
|
||||
| data[3];
|
||||
|
||||
*buffer += 4;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
char* guac_common_ssh_buffer_read_string(char** buffer, int* length) {
|
||||
|
||||
char* value;
|
||||
|
||||
*length = guac_common_ssh_buffer_read_uint32(buffer);
|
||||
value = *buffer;
|
||||
|
||||
*buffer += *length;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
134
src/common-ssh/common-ssh/buffer.h
Normal file
134
src/common-ssh/common-ssh/buffer.h
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_SSH_BUFFER_H
|
||||
#define GUAC_COMMON_SSH_BUFFER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Writes the given byte to the given buffer, advancing the buffer pointer by
|
||||
* one byte.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to write to.
|
||||
*
|
||||
* @param value
|
||||
* The value to write.
|
||||
*/
|
||||
void guac_common_ssh_buffer_write_byte(char** buffer, uint8_t value);
|
||||
|
||||
/**
|
||||
* Writes the given integer to the given buffer, advancing the buffer pointer
|
||||
* four bytes.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to write to.
|
||||
*
|
||||
* @param value
|
||||
* The value to write.
|
||||
*/
|
||||
void guac_common_ssh_buffer_write_uint32(char** buffer, uint32_t value);
|
||||
|
||||
/**
|
||||
* Writes the given string and its length to the given buffer, advancing the
|
||||
* buffer pointer by the size of the length (four bytes) and the size of the
|
||||
* string.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to write to.
|
||||
*
|
||||
* @param string
|
||||
* The string value to write.
|
||||
*
|
||||
* @param length
|
||||
* The length of the string to write, in bytes.
|
||||
*/
|
||||
void guac_common_ssh_buffer_write_string(char** buffer, const char* string,
|
||||
int length);
|
||||
|
||||
/**
|
||||
* Writes the given BIGNUM the given buffer, advancing the buffer pointer by
|
||||
* the size of the length (four bytes) and the size of the BIGNUM.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to write to.
|
||||
*
|
||||
* @param value
|
||||
* The value to write.
|
||||
*/
|
||||
void guac_common_ssh_buffer_write_bignum(char** buffer, const BIGNUM* value);
|
||||
|
||||
/**
|
||||
* Writes the given data the given buffer, advancing the buffer pointer by the
|
||||
* given length.
|
||||
*
|
||||
* @param data
|
||||
* The arbitrary data to write.
|
||||
*
|
||||
* @param length
|
||||
* The length of data to write, in bytes.
|
||||
*/
|
||||
void guac_common_ssh_buffer_write_data(char** buffer, const char* data, int length);
|
||||
|
||||
/**
|
||||
* Reads a single byte from the given buffer, advancing the buffer by one byte.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to read from.
|
||||
*
|
||||
* @return
|
||||
* The value read from the buffer.
|
||||
*/
|
||||
uint8_t guac_common_ssh_buffer_read_byte(char** buffer);
|
||||
|
||||
/**
|
||||
* Reads an integer from the given buffer, advancing the buffer by four bytes.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to read from.
|
||||
*
|
||||
* @return
|
||||
* The value read from the buffer.
|
||||
*/
|
||||
uint32_t guac_common_ssh_buffer_read_uint32(char** buffer);
|
||||
|
||||
/**
|
||||
* Reads a string and its length from the given buffer, advancing the buffer
|
||||
* by the size of the length (four bytes) and the size of the string, and
|
||||
* returning a pointer to the buffer. The length of the string is stored in
|
||||
* the given int.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to read from.
|
||||
*
|
||||
* @param length
|
||||
* A pointer to an integer into which the length of the read string will
|
||||
* be stored.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the value within the buffer.
|
||||
*/
|
||||
char* guac_common_ssh_buffer_read_string(char** buffer, int* length);
|
||||
|
||||
#endif
|
||||
|
152
src/common-ssh/common-ssh/key.h
Normal file
152
src/common-ssh/common-ssh/key.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_SSH_KEY_H
|
||||
#define GUAC_COMMON_SSH_KEY_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <libssh2.h>
|
||||
|
||||
/**
|
||||
* OpenSSH v1 private keys are PEM-wrapped base64-encoded blobs. The encoded data begins with:
|
||||
* "openssh-key-v1\0"
|
||||
*/
|
||||
#define OPENSSH_V1_KEY_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEA"
|
||||
|
||||
/**
|
||||
* The base64-encoded prefix indicating an OpenSSH v1 private key is NOT protected by a
|
||||
* passphrase. Specifically, it is the following data fields and values:
|
||||
* pascal string: cipher name ("none")
|
||||
* pascal string: kdf name ("none")
|
||||
* pascal string: kdf params (NULL)
|
||||
* 32-bit int: number of keys (1)
|
||||
*/
|
||||
#define OPENSSH_V1_UNENCRYPTED_KEY "AAAABG5vbmUAAAAEbm9uZQAAAAAAAAAB"
|
||||
|
||||
/**
|
||||
* Abstraction of a key used for SSH authentication.
|
||||
*/
|
||||
typedef struct guac_common_ssh_key {
|
||||
|
||||
/**
|
||||
* The private key, encoded as necessary for SSH.
|
||||
*/
|
||||
char* private_key;
|
||||
|
||||
/**
|
||||
* The length of the private key, in bytes.
|
||||
*/
|
||||
int private_key_length;
|
||||
|
||||
/**
|
||||
* The private key's passphrase, if any.
|
||||
*/
|
||||
char *passphrase;
|
||||
|
||||
} guac_common_ssh_key;
|
||||
|
||||
/**
|
||||
* Allocates a new key containing the given private key data and specified
|
||||
* passphrase. If unable to read the key, NULL is returned.
|
||||
*
|
||||
* @param data
|
||||
* The base64-encoded data to decode when reading the key.
|
||||
*
|
||||
* @param length
|
||||
* The length of the provided data, in bytes.
|
||||
*
|
||||
* @param passphrase
|
||||
* The passphrase to use when decrypting the key, if any, or an empty
|
||||
* string or NULL if no passphrase is needed.
|
||||
*
|
||||
* @return
|
||||
* The decoded, decrypted private key, or NULL if the key could not be
|
||||
* decoded.
|
||||
*/
|
||||
guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length,
|
||||
char* passphrase);
|
||||
|
||||
/**
|
||||
* Returns a statically-allocated string describing the most recent SSH key
|
||||
* error.
|
||||
*
|
||||
* @return
|
||||
* A statically-allocated string describing the most recent SSH key error.
|
||||
*/
|
||||
const char* guac_common_ssh_key_error();
|
||||
|
||||
/**
|
||||
* Frees all memory associated with the given key.
|
||||
*
|
||||
* @param key
|
||||
* The key to free.
|
||||
*/
|
||||
void guac_common_ssh_key_free(guac_common_ssh_key* key);
|
||||
|
||||
/**
|
||||
* Verifies the host key for the given hostname/port combination against
|
||||
* one or more known_hosts entries. The known_host entries can either be a
|
||||
* single host_key, provided by the client, or a set of known_hosts entries
|
||||
* provided in the /etc/guacamole/ssh_known_hosts file. Failure to correctly
|
||||
* load the known_hosts entries will result in a connection abort and a returned
|
||||
* error code. A return code of zero indiciates that either no known_hosts entries
|
||||
* were provided, or that the verification succeeded (match). Negative values
|
||||
* indicate internal libssh2 error codes; positive values indicate a failure
|
||||
* during verification of the host key against the known hosts.
|
||||
*
|
||||
* @param session
|
||||
* A pointer to the LIBSSH2_SESSION structure of the SSH connection already
|
||||
* in progress.
|
||||
*
|
||||
* @param client
|
||||
* The current guac_client instance for which the known_hosts checking is
|
||||
* being performed.
|
||||
*
|
||||
* @param host_key
|
||||
* The known host entry provided by the client. If this is non-null and not
|
||||
* empty, it will be the only host key loaded and used for verification. If
|
||||
* this is null or empty an attempt will be made to read the
|
||||
* /etc/guacamole/ssh_known_hosts file and load entries from it.
|
||||
*
|
||||
* @param hostname
|
||||
* The hostname or IP of the server that is being verified.
|
||||
*
|
||||
* @param port
|
||||
* The port number of the server being verified.
|
||||
*
|
||||
* @param remote_hostkey
|
||||
* The host key of the remote system being verified.
|
||||
*
|
||||
* @param remote_hostkey_len
|
||||
* The length of the remote host key being verified
|
||||
*
|
||||
* @return
|
||||
* The status of the known_hosts check. This will be zero if no entries
|
||||
* are provided or if the match succeeds, negative to indicate internal
|
||||
* libssh2 errors, or positive to indicate failures during host key
|
||||
* checking.
|
||||
*/
|
||||
int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
|
||||
const char* host_key, const char* hostname, int port, const char* remote_hostkey,
|
||||
const size_t remote_hostkey_len);
|
||||
|
||||
#endif
|
||||
|
301
src/common-ssh/common-ssh/sftp.h
Normal file
301
src/common-ssh/common-ssh/sftp.h
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_SSH_SFTP_H
|
||||
#define GUAC_COMMON_SSH_SFTP_H
|
||||
|
||||
#include "common/json.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#include <guacamole/object.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
/**
|
||||
* Maximum number of bytes per path.
|
||||
*/
|
||||
#define GUAC_COMMON_SSH_SFTP_MAX_PATH 2048
|
||||
|
||||
/**
|
||||
* Maximum number of path components per path.
|
||||
*/
|
||||
#define GUAC_COMMON_SSH_SFTP_MAX_DEPTH 1024
|
||||
|
||||
/**
|
||||
* Representation of an SFTP-driven filesystem object. Unlike guac_object, this
|
||||
* structure is not tied to any particular user.
|
||||
*/
|
||||
typedef struct guac_common_ssh_sftp_filesystem {
|
||||
|
||||
/**
|
||||
* The human-readable display name of this filesystem.
|
||||
*/
|
||||
char* name;
|
||||
|
||||
/**
|
||||
* The distinct SSH session used for SFTP.
|
||||
*/
|
||||
guac_common_ssh_session* ssh_session;
|
||||
|
||||
/**
|
||||
* SFTP session, used for file transfers.
|
||||
*/
|
||||
LIBSSH2_SFTP* sftp_session;
|
||||
|
||||
/**
|
||||
* The path to the directory to expose to the user as a filesystem object.
|
||||
*/
|
||||
char root_path[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
/**
|
||||
* The path files will be sent to, if uploaded directly via a "file"
|
||||
* instruction.
|
||||
*/
|
||||
char upload_path[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
/**
|
||||
* If downloads from SFTP to the local browser should be disabled.
|
||||
*/
|
||||
int disable_download;
|
||||
|
||||
/**
|
||||
* If uploads from the local browser to SFTP should be disabled.
|
||||
*/
|
||||
int disable_upload;
|
||||
|
||||
} guac_common_ssh_sftp_filesystem;
|
||||
|
||||
/**
|
||||
* The current state of a directory listing operation.
|
||||
*/
|
||||
typedef struct guac_common_ssh_sftp_ls_state {
|
||||
|
||||
/**
|
||||
* The SFTP filesystem being listed.
|
||||
*/
|
||||
guac_common_ssh_sftp_filesystem* filesystem;
|
||||
|
||||
/**
|
||||
* Reference to the directory currently being listed over SFTP. This
|
||||
* directory must already be open from a call to libssh2_sftp_opendir().
|
||||
*/
|
||||
LIBSSH2_SFTP_HANDLE* directory;
|
||||
|
||||
/**
|
||||
* The absolute path of the directory being listed.
|
||||
*/
|
||||
char directory_name[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
/**
|
||||
* The current state of the JSON directory object being written.
|
||||
*/
|
||||
guac_common_json_state json_state;
|
||||
|
||||
} guac_common_ssh_sftp_ls_state;
|
||||
|
||||
/**
|
||||
* Creates a new Guacamole filesystem object which provides access to files
|
||||
* and directories via SFTP using the given SSH session. When the filesystem
|
||||
* will no longer be used, it must be explicitly destroyed with
|
||||
* guac_common_ssh_destroy_sftp_filesystem(). The resulting object is not
|
||||
* automatically exposed to users of the connection - filesystem operations
|
||||
* must be mediated either through various handlers or through exposing a
|
||||
* filesystem guac_object via guac_common_ssh_alloc_sftp_filesystem_object().
|
||||
*
|
||||
* @param session
|
||||
* The session to use to provide SFTP. This session will automatically be
|
||||
* destroyed when this filesystem is destroyed.
|
||||
*
|
||||
* @param root_path
|
||||
* The path accessible via SFTP to consider the root path of the filesystem
|
||||
* exposed to the user. Only the contents of this path will be available
|
||||
* via the filesystem object.
|
||||
*
|
||||
* @param name
|
||||
* The name to send as the name of the filesystem whenever it is exposed
|
||||
* to a user, or NULL to automatically generate a name from the provided
|
||||
* root_path.
|
||||
*
|
||||
* @param disable_download
|
||||
* Whether downloads from the SFTP share to the local browser should be
|
||||
* disabled.
|
||||
*
|
||||
* @param disable_upload
|
||||
* Whether uploads from the local browser to SFTP should be disabled.
|
||||
*
|
||||
* @return
|
||||
* A new SFTP filesystem object, not yet exposed to users.
|
||||
*/
|
||||
guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem(
|
||||
guac_common_ssh_session* session, const char* root_path,
|
||||
const char* name, int disable_download, int disable_upload);
|
||||
|
||||
/**
|
||||
* Destroys the given filesystem object, disconnecting from SFTP and freeing
|
||||
* and associated resources. Any associated session or user objects must be
|
||||
* explicitly destroyed.
|
||||
*
|
||||
* @param filesystem
|
||||
* The filesystem object to destroy.
|
||||
*/
|
||||
void guac_common_ssh_destroy_sftp_filesystem(
|
||||
guac_common_ssh_sftp_filesystem* filesystem);
|
||||
|
||||
/**
|
||||
* Creates and exposes a new filesystem guac_object to the given user,
|
||||
* providing access to the files within the given SFTP filesystem. The
|
||||
* allocated guac_object must eventually be freed via guac_user_free_object().
|
||||
*
|
||||
* @param filesystem
|
||||
* The filesystem object to expose.
|
||||
*
|
||||
* @param user
|
||||
* The user that the SFTP filesystem should be exposed to.
|
||||
*
|
||||
* @return
|
||||
* A new Guacamole filesystem object, configured to use SFTP for uploading
|
||||
* and downloading files.
|
||||
*/
|
||||
guac_object* guac_common_ssh_alloc_sftp_filesystem_object(
|
||||
guac_common_ssh_sftp_filesystem* filesystem, guac_user* user);
|
||||
|
||||
/**
|
||||
* Allocates a new filesystem guac_object for the given user, returning the
|
||||
* resulting guac_object. This function is provided for convenience, as it is
|
||||
* can be used as the callback for guac_client_foreach_user() or
|
||||
* guac_client_for_owner(). Note that this guac_object will be tracked
|
||||
* internally by libguac, will be provided to us in the parameters of handlers
|
||||
* related to that guac_object, and will automatically be freed when the
|
||||
* associated guac_user is freed, so the return value of this function can
|
||||
* safely be ignored.
|
||||
*
|
||||
* If either the given user or the given filesystem are NULL, then this
|
||||
* function has no effect.
|
||||
*
|
||||
* @param user
|
||||
* The use to expose the filesystem to, or NULL if nothing should be
|
||||
* exposed.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to the guac_common_ssh_sftp_filesystem instance to expose
|
||||
* to the given user, or NULL if nothing should be exposed.
|
||||
*
|
||||
* @return
|
||||
* The guac_object allocated for the newly-exposed filesystem, or NULL if
|
||||
* no filesystem object could be allocated.
|
||||
*/
|
||||
void* guac_common_ssh_expose_sftp_filesystem(guac_user* user, void* data);
|
||||
|
||||
/**
|
||||
* Initiates an SFTP file download to the user via the Guacamole "file"
|
||||
* instruction. The download will be automatically monitored and continued
|
||||
* after this function terminates in response to "ack" instructions received by
|
||||
* the user.
|
||||
*
|
||||
* @param filesystem
|
||||
* The filesystem containing the file to be downloaded.
|
||||
*
|
||||
* @param user
|
||||
* The user that should receive the file (via a "file" instruction).
|
||||
*
|
||||
* @param filename
|
||||
* The filename of the file to download, relative to the given filesystem.
|
||||
*
|
||||
* @return
|
||||
* The file stream created for the file download, already configured to
|
||||
* properly handle "ack" responses, etc. from the user.
|
||||
*/
|
||||
guac_stream* guac_common_ssh_sftp_download_file(
|
||||
guac_common_ssh_sftp_filesystem* filesystem, guac_user* user,
|
||||
char* filename);
|
||||
|
||||
/**
|
||||
* Handles an incoming stream from a Guacamole "file" instruction, saving the
|
||||
* contents of that stream to the file having the given name within the
|
||||
* upload directory set by guac_common_ssh_sftp_set_upload_path().
|
||||
*
|
||||
* @param filesystem
|
||||
* The filesystem that should receive the uploaded file.
|
||||
*
|
||||
* @param user
|
||||
* The user who is attempting to open the file stream (the user that sent
|
||||
* the "file" instruction).
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the uploaded file data will be received.
|
||||
*
|
||||
* @param mimetype
|
||||
* The mimetype of the data being received.
|
||||
*
|
||||
* @param filename
|
||||
* The filename of the file to write to. This filename will always be taken
|
||||
* relative to the upload path set by
|
||||
* guac_common_ssh_sftp_set_upload_path().
|
||||
*
|
||||
* @return
|
||||
* Zero if the incoming stream has been handled successfully, non-zero on
|
||||
* failure.
|
||||
*/
|
||||
int guac_common_ssh_sftp_handle_file_stream(
|
||||
guac_common_ssh_sftp_filesystem* filesystem, guac_user* user,
|
||||
guac_stream* stream, char* mimetype, char* filename);
|
||||
|
||||
/**
|
||||
* Set the destination directory for future uploads submitted via
|
||||
* guac_common_ssh_sftp_handle_file_stream(). This function has no bearing
|
||||
* on the destination directories of files uploaded with "put" instructions.
|
||||
*
|
||||
* @param filesystem
|
||||
* The filesystem to set the upload path of.
|
||||
*
|
||||
* @param path
|
||||
* The path to use for future uploads submitted via the
|
||||
* guac_common_ssh_sftp_handle_file_stream() function.
|
||||
*/
|
||||
void guac_common_ssh_sftp_set_upload_path(
|
||||
guac_common_ssh_sftp_filesystem* filesystem, const char* path);
|
||||
|
||||
/**
|
||||
* Given an arbitrary absolute path, which may contain "..", ".", and
|
||||
* backslashes, creates an equivalent absolute path which does NOT contain
|
||||
* relative path components (".." or "."), backslashes, or empty path
|
||||
* components. With the exception of paths referring to the root directory, the
|
||||
* resulting path is guaranteed to not contain trailing slashes.
|
||||
*
|
||||
* Normalization will fail if the given path is not absolute, is too long, or
|
||||
* contains more than GUAC_COMMON_SSH_SFTP_MAX_DEPTH path components.
|
||||
*
|
||||
* @param fullpath
|
||||
* The buffer to populate with the normalized path. The normalized path
|
||||
* will not contain relative path components like ".." or ".", nor will it
|
||||
* contain backslashes. This buffer MUST be at least
|
||||
* GUAC_COMMON_SSH_SFTP_MAX_PATH bytes in size.
|
||||
*
|
||||
* @param path
|
||||
* The absolute path to normalize.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if normalization succeeded, zero otherwise.
|
||||
*/
|
||||
int guac_common_ssh_sftp_normalize_path(char* fullpath,
|
||||
const char* path);
|
||||
|
||||
#endif
|
||||
|
155
src/common-ssh/common-ssh/ssh.h
Normal file
155
src/common-ssh/common-ssh/ssh.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_SSH_H
|
||||
#define GUAC_COMMON_SSH_H
|
||||
|
||||
#include "user.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <libssh2.h>
|
||||
|
||||
/**
|
||||
* Handler for retrieving additional credentials.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole Client associated with this need for additional
|
||||
* credentials.
|
||||
*
|
||||
* @param cred_name
|
||||
* The name of the credential being requested, which will be shared
|
||||
* with the client in order to generate a meaningful prompt.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated string containing the credentials provided by
|
||||
* the user, which must be freed by a call to free().
|
||||
*/
|
||||
typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name);
|
||||
|
||||
/**
|
||||
* An SSH session, backed by libssh2 and associated with a particular
|
||||
* Guacamole client.
|
||||
*/
|
||||
typedef struct guac_common_ssh_session {
|
||||
|
||||
/**
|
||||
* The Guacamole client using this SSH session.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The user that will be authenticating via SSH.
|
||||
*/
|
||||
guac_common_ssh_user* user;
|
||||
|
||||
/**
|
||||
* The underlying SSH session from libssh2.
|
||||
*/
|
||||
LIBSSH2_SESSION* session;
|
||||
|
||||
/**
|
||||
* The file descriptor of the socket being used for the SSH connection.
|
||||
*/
|
||||
int fd;
|
||||
|
||||
/**
|
||||
* Callback function to retrieve credentials.
|
||||
*/
|
||||
guac_ssh_credential_handler* credential_handler;
|
||||
|
||||
} guac_common_ssh_session;
|
||||
|
||||
/**
|
||||
* Initializes the underlying SSH and encryption libraries used by Guacamole.
|
||||
* This function must be called before any other guac_common_ssh_*() functions
|
||||
* are called.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole client that will be using SSH.
|
||||
*
|
||||
* @return
|
||||
* Zero if initialization, or non-zero if an error occurs.
|
||||
*/
|
||||
int guac_common_ssh_init(guac_client* client);
|
||||
|
||||
/**
|
||||
* Cleans up the underlying SSH and encryption libraries used by Guacamole.
|
||||
* This function must be called once no other guac_common_ssh_*() functions
|
||||
* will be used.
|
||||
*/
|
||||
void guac_common_ssh_uninit();
|
||||
|
||||
/**
|
||||
* Connects to the SSH server running at the given hostname and port, and
|
||||
* authenticates as the given user. If an error occurs while connecting or
|
||||
* authenticating, the Guacamole client will automatically and fatally abort.
|
||||
* The user object provided must eventually be explicitly destroyed, but should
|
||||
* not be destroyed until this session is destroyed, assuming the session is
|
||||
* successfully created.
|
||||
*
|
||||
* @param client
|
||||
* The Guacamole client that will be using SSH.
|
||||
*
|
||||
* @param hostname
|
||||
* The hostname of the SSH server to connect to.
|
||||
*
|
||||
* @param port
|
||||
* The port to connect to on the given hostname.
|
||||
*
|
||||
* @param user
|
||||
* The user to authenticate as, once connected.
|
||||
*
|
||||
* @param keepalive
|
||||
* How frequently the connection should send keepalive packets, in
|
||||
* seconds. Zero disables keepalive packets, and 2 is the minimum
|
||||
* configurable value.
|
||||
*
|
||||
* @param host_key
|
||||
* The known public host key of the server, as provided by the client. If
|
||||
* provided the identity of the server will be checked against this key,
|
||||
* and a mis-match between this and the server identity will cause the
|
||||
* connection to fail. If not provided, no checks will be done and the
|
||||
* connection will proceed.
|
||||
*
|
||||
* @param credential_handler
|
||||
* The handler function for retrieving additional credentials from the user
|
||||
* as required by the SSH server, or NULL if the user will not be asked
|
||||
* for additional credentials.
|
||||
*
|
||||
* @return
|
||||
* A new SSH session if the connection and authentication succeed, or NULL
|
||||
* if the connection or authentication were not successful.
|
||||
*/
|
||||
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
const char* hostname, const char* port, guac_common_ssh_user* user,
|
||||
int keepalive, const char* host_key,
|
||||
guac_ssh_credential_handler* credential_handler);
|
||||
|
||||
/**
|
||||
* Disconnects and destroys the given SSH session, freeing all associated
|
||||
* resources. Any associated user must be explicitly destroyed, and will not
|
||||
* be destroyed automatically.
|
||||
*
|
||||
* @param session
|
||||
* The SSH session to destroy.
|
||||
*/
|
||||
void guac_common_ssh_destroy_session(guac_common_ssh_session* session);
|
||||
|
||||
#endif
|
||||
|
108
src/common-ssh/common-ssh/user.h
Normal file
108
src/common-ssh/common-ssh/user.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_SSH_USER_H
|
||||
#define GUAC_COMMON_SSH_USER_H
|
||||
|
||||
#include "key.h"
|
||||
|
||||
/**
|
||||
* Data describing an SSH user, including their credentials.
|
||||
*/
|
||||
typedef struct guac_common_ssh_user {
|
||||
|
||||
/**
|
||||
* The username of this user.
|
||||
*/
|
||||
char* username;
|
||||
|
||||
/**
|
||||
* The password which should be used to authenticate this user, if any, or
|
||||
* NULL if a private key will be used instead.
|
||||
*/
|
||||
char* password;
|
||||
|
||||
/**
|
||||
* The private key which should be used to authenticate this user, if any,
|
||||
* or NULL if a password will be used instead.
|
||||
*/
|
||||
guac_common_ssh_key* private_key;
|
||||
|
||||
} guac_common_ssh_user;
|
||||
|
||||
/**
|
||||
* Creates a new SSH user with the given username. When additionally populated
|
||||
* with a password or private key, this user can then be used for
|
||||
* authentication.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user being created.
|
||||
*
|
||||
* @return
|
||||
* A new SSH user having the given username, but no associated password
|
||||
* or private key.
|
||||
*/
|
||||
guac_common_ssh_user* guac_common_ssh_create_user(const char* username);
|
||||
|
||||
/**
|
||||
* Destroys the given user object, releasing all associated resources.
|
||||
*
|
||||
* @param user
|
||||
* The user to destroy.
|
||||
*/
|
||||
void guac_common_ssh_destroy_user(guac_common_ssh_user* user);
|
||||
|
||||
/**
|
||||
* Associates the given user with the given password, such that that password
|
||||
* is used for future authentication attempts.
|
||||
*
|
||||
* @param user
|
||||
* The user to associate with the given password.
|
||||
*
|
||||
* @param password
|
||||
* The password to associate with the given user.
|
||||
*/
|
||||
void guac_common_ssh_user_set_password(guac_common_ssh_user* user,
|
||||
const char* password);
|
||||
|
||||
/**
|
||||
* Imports the given private key, associating that key with the given user. If
|
||||
* necessary to decrypt the key, a passphrase may be specified. The private key
|
||||
* must be provided in base64 form. If the private key is imported
|
||||
* successfully, it will be used for future authentication attempts.
|
||||
*
|
||||
* @param user
|
||||
* The user to associate with the given private key.
|
||||
*
|
||||
* @param private_key
|
||||
* The base64-encoded private key to import.
|
||||
*
|
||||
* @param passphrase
|
||||
* The passphrase to use to decrypt the given private key, or NULL if no
|
||||
* passphrase should be used.
|
||||
*
|
||||
* @return
|
||||
* Zero if the private key is successfully imported, or non-zero if the
|
||||
* private key could not be imported due to an error.
|
||||
*/
|
||||
int guac_common_ssh_user_import_key(guac_common_ssh_user* user,
|
||||
char* private_key, char* passphrase);
|
||||
|
||||
#endif
|
||||
|
248
src/common-ssh/key.c
Normal file
248
src/common-ssh/key.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common-ssh/buffer.h"
|
||||
#include "common-ssh/key.h"
|
||||
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Check for a PKCS#1/PKCS#8 ENCRYPTED marker.
|
||||
*
|
||||
* @param data
|
||||
* The buffer to scan.
|
||||
* @param length
|
||||
* The length of the buffer.
|
||||
*
|
||||
* @return
|
||||
* True if the buffer contains the marker, false otherwise.
|
||||
*/
|
||||
static bool is_pkcs_encrypted_key(char* data, int length) {
|
||||
return guac_strnstr(data, "ENCRYPTED", length) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a PEM header & initial base64-encoded data indicating this is an
|
||||
* OpenSSH v1 key.
|
||||
*
|
||||
* @param data
|
||||
* The buffer to scan.
|
||||
* @param length
|
||||
* The length of the buffer.
|
||||
*
|
||||
* @return
|
||||
* True if the buffer contains a private key, false otherwise.
|
||||
*/
|
||||
static bool is_ssh_private_key(char* data, int length) {
|
||||
if (length < sizeof(OPENSSH_V1_KEY_HEADER) - 1) {
|
||||
return false;
|
||||
}
|
||||
return !strncmp(data, OPENSSH_V1_KEY_HEADER, sizeof(OPENSSH_V1_KEY_HEADER) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming an offset into a key past the header, check for the base64-encoded
|
||||
* data indicating this key is not protected by a passphrase.
|
||||
*
|
||||
* @param data
|
||||
* The buffer to scan.
|
||||
* @param length
|
||||
* The length of the buffer.
|
||||
*
|
||||
* @return
|
||||
* True if the buffer contains an unencrypted key, false otherwise.
|
||||
*/
|
||||
static bool is_ssh_key_unencrypted(char* data, int length) {
|
||||
if (length < sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1) {
|
||||
return false;
|
||||
}
|
||||
return !strncmp(data, OPENSSH_V1_UNENCRYPTED_KEY, sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* A passphrase is needed if the key is an encrypted PKCS#1/PKCS#8 key OR if
|
||||
* the key is both an OpenSSH v1 key AND there isn't a marker indicating the
|
||||
* key is unprotected.
|
||||
*
|
||||
* @param data
|
||||
* The buffer to scan.
|
||||
* @param length
|
||||
* The length of the buffer.
|
||||
*
|
||||
* @return
|
||||
* True if the buffer contains a key needing a passphrase, false otherwise.
|
||||
*/
|
||||
static bool is_passphrase_needed(char* data, int length) {
|
||||
/* Is this an encrypted PKCS#1/PKCS#8 key? */
|
||||
if (is_pkcs_encrypted_key(data, length)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Is this an OpenSSH v1 key? */
|
||||
if (is_ssh_private_key(data, length)) {
|
||||
/* This is safe due to the check in is_ssh_private_key. */
|
||||
data += sizeof(OPENSSH_V1_KEY_HEADER) - 1;
|
||||
length -= sizeof(OPENSSH_V1_KEY_HEADER) - 1;
|
||||
/* If this is NOT unprotected, we need a passphrase. */
|
||||
if (!is_ssh_key_unencrypted(data, length)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length,
|
||||
char* passphrase) {
|
||||
|
||||
/* Because libssh2 will do the actual key parsing (to let it deal with
|
||||
* different key algorithms) we need to perform a heuristic here to check
|
||||
* if a passphrase is needed. This could allow junk keys through that
|
||||
* would never be able to auth. libssh2 should display errors to help
|
||||
* admins track down malformed keys and delete or replace them.
|
||||
*/
|
||||
|
||||
if (is_passphrase_needed(data, length) && (passphrase == NULL || *passphrase == '\0'))
|
||||
return NULL;
|
||||
|
||||
guac_common_ssh_key* key = malloc(sizeof(guac_common_ssh_key));
|
||||
|
||||
/* Copy private key to structure */
|
||||
key->private_key_length = length;
|
||||
key->private_key = malloc(length);
|
||||
memcpy(key->private_key, data, length);
|
||||
key->passphrase = strdup(passphrase);
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
const char* guac_common_ssh_key_error() {
|
||||
|
||||
/* Return static error string */
|
||||
return ERR_reason_error_string(ERR_get_error());
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_key_free(guac_common_ssh_key* key) {
|
||||
|
||||
free(key->private_key);
|
||||
free(key->passphrase);
|
||||
free(key);
|
||||
}
|
||||
|
||||
int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
|
||||
const char* host_key, const char* hostname, int port, const char* remote_hostkey,
|
||||
const size_t remote_hostkey_len) {
|
||||
|
||||
LIBSSH2_KNOWNHOSTS* ssh_known_hosts = libssh2_knownhost_init(session);
|
||||
int known_hosts = 0;
|
||||
|
||||
/* Add host key provided from settings */
|
||||
if (host_key && strcmp(host_key, "") != 0) {
|
||||
|
||||
known_hosts = libssh2_knownhost_readline(ssh_known_hosts, host_key, strlen(host_key),
|
||||
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
|
||||
|
||||
/* readline function returns 0 on success, so we increment to indicate a valid entry */
|
||||
if (known_hosts == 0)
|
||||
known_hosts++;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, we look for a ssh_known_hosts file within GUACAMOLE_HOME and read that in. */
|
||||
else {
|
||||
|
||||
const char *guac_known_hosts = "/etc/guacamole/ssh_known_hosts";
|
||||
if (access(guac_known_hosts, F_OK) != -1)
|
||||
known_hosts = libssh2_knownhost_readfile(ssh_known_hosts, guac_known_hosts, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
|
||||
|
||||
}
|
||||
|
||||
/* If there's an error provided, abort connection and return that. */
|
||||
if (known_hosts < 0) {
|
||||
|
||||
char* errmsg;
|
||||
int errval = libssh2_session_last_error(session, &errmsg, NULL, 0);
|
||||
guac_client_log(client, GUAC_LOG_ERROR,
|
||||
"Error %d trying to load SSH host keys: %s", errval, errmsg);
|
||||
|
||||
libssh2_knownhost_free(ssh_known_hosts);
|
||||
return known_hosts;
|
||||
|
||||
}
|
||||
|
||||
/* No host keys were loaded, so we bail out checking and continue the connection. */
|
||||
else if (known_hosts == 0) {
|
||||
guac_client_log(client, GUAC_LOG_WARNING,
|
||||
"No known host keys provided, host identity will not be verified.");
|
||||
libssh2_knownhost_free(ssh_known_hosts);
|
||||
return known_hosts;
|
||||
}
|
||||
|
||||
|
||||
/* Check remote host key against known hosts */
|
||||
int kh_check = libssh2_knownhost_checkp(ssh_known_hosts, hostname, port,
|
||||
remote_hostkey, remote_hostkey_len,
|
||||
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
|
||||
LIBSSH2_KNOWNHOST_KEYENC_RAW,
|
||||
NULL);
|
||||
|
||||
/* Deal with the return of the host key check */
|
||||
switch (kh_check) {
|
||||
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Host key match found for %s", hostname);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
|
||||
guac_client_log(client, GUAC_LOG_ERROR,
|
||||
"Host key not found for %s.", hostname);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
|
||||
guac_client_log(client, GUAC_LOG_ERROR,
|
||||
"Host key does not match known hosts entry for %s", hostname);
|
||||
break;
|
||||
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
|
||||
default:
|
||||
guac_client_log(client, GUAC_LOG_ERROR,
|
||||
"Host %s could not be checked against known hosts.",
|
||||
hostname);
|
||||
}
|
||||
|
||||
/* Return the check value */
|
||||
libssh2_knownhost_free(ssh_known_hosts);
|
||||
return kh_check;
|
||||
|
||||
}
|
1016
src/common-ssh/sftp.c
Normal file
1016
src/common-ssh/sftp.c
Normal file
File diff suppressed because it is too large
Load Diff
602
src/common-ssh/ssh.c
Normal file
602
src/common-ssh/ssh.c
Normal file
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common-ssh/key.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
#include "common-ssh/user.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/fips.h>
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifdef LIBSSH2_USES_GCRYPT
|
||||
#include <gcrypt.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef LIBSSH2_USES_GCRYPT
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A list of all key exchange algorithms that are both FIPS-compliant, and
|
||||
* OpenSSL-supported. Note that "ext-info-c" is also included. While not a key
|
||||
* exchange algorithm per se, it must be in the list to ensure that the server
|
||||
* will send a SSH_MSG_EXT_INFO response, which is required to perform RSA key
|
||||
* upgrades.
|
||||
*/
|
||||
#define FIPS_COMPLIANT_KEX_ALGORITHMS "diffie-hellman-group-exchange-sha256,ext-info-c"
|
||||
|
||||
/**
|
||||
* A list of ciphers that are both FIPS-compliant, and OpenSSL-supported.
|
||||
*/
|
||||
#define FIPS_COMPLIANT_CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"
|
||||
|
||||
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
|
||||
/**
|
||||
* Array of mutexes, used by OpenSSL.
|
||||
*/
|
||||
static pthread_mutex_t* guac_common_ssh_openssl_locks = NULL;
|
||||
|
||||
/**
|
||||
* Called by OpenSSL when locking or unlocking the Nth mutex.
|
||||
*
|
||||
* @param mode
|
||||
* A bitmask denoting the action to be taken on the Nth lock, such as
|
||||
* CRYPTO_LOCK or CRYPTO_UNLOCK.
|
||||
*
|
||||
* @param n
|
||||
* The index of the lock to lock or unlock.
|
||||
*
|
||||
* @param file
|
||||
* The filename of the function setting the lock, for debugging purposes.
|
||||
*
|
||||
* @param line
|
||||
* The line number of the function setting the lock, for debugging
|
||||
* purposes.
|
||||
*/
|
||||
static void guac_common_ssh_openssl_locking_callback(int mode, int n,
|
||||
const char* file, int line){
|
||||
|
||||
/* Lock given mutex upon request */
|
||||
if (mode & CRYPTO_LOCK)
|
||||
pthread_mutex_lock(&(guac_common_ssh_openssl_locks[n]));
|
||||
|
||||
/* Unlock given mutex upon request */
|
||||
else if (mode & CRYPTO_UNLOCK)
|
||||
pthread_mutex_unlock(&(guac_common_ssh_openssl_locks[n]));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by OpenSSL when determining the current thread ID.
|
||||
*
|
||||
* @return
|
||||
* An ID which uniquely identifies the current thread.
|
||||
*/
|
||||
static unsigned long guac_common_ssh_openssl_id_callback() {
|
||||
return (unsigned long) pthread_self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the given number of mutexes, such that OpenSSL will have at least
|
||||
* this number of mutexes at its disposal.
|
||||
*
|
||||
* @param count
|
||||
* The number of mutexes (locks) to create.
|
||||
*/
|
||||
static void guac_common_ssh_openssl_init_locks(int count) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Allocate required number of locks */
|
||||
guac_common_ssh_openssl_locks =
|
||||
malloc(sizeof(pthread_mutex_t) * count);
|
||||
|
||||
/* Initialize each lock */
|
||||
for (i=0; i < count; i++)
|
||||
pthread_mutex_init(&(guac_common_ssh_openssl_locks[i]), NULL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the given number of mutexes.
|
||||
*
|
||||
* @param count
|
||||
* The number of mutexes (locks) to free.
|
||||
*/
|
||||
static void guac_common_ssh_openssl_free_locks(int count) {
|
||||
|
||||
int i;
|
||||
|
||||
/* SSL lock array was not initialized */
|
||||
if (guac_common_ssh_openssl_locks == NULL)
|
||||
return;
|
||||
|
||||
/* Free all locks */
|
||||
for (i=0; i < count; i++)
|
||||
pthread_mutex_destroy(&(guac_common_ssh_openssl_locks[i]));
|
||||
|
||||
/* Free lock array */
|
||||
free(guac_common_ssh_openssl_locks);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int guac_common_ssh_init(guac_client* client) {
|
||||
|
||||
#ifdef LIBSSH2_USES_GCRYPT
|
||||
|
||||
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
|
||||
|
||||
/* Init threadsafety in libgcrypt */
|
||||
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
|
||||
/* Initialize GCrypt */
|
||||
if (!gcry_check_version(GCRYPT_VERSION)) {
|
||||
guac_client_log(client, GUAC_LOG_ERROR, "libgcrypt version mismatch.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mark initialization as completed. */
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
|
||||
/* Init threadsafety in OpenSSL */
|
||||
guac_common_ssh_openssl_init_locks(CRYPTO_num_locks());
|
||||
CRYPTO_set_id_callback(guac_common_ssh_openssl_id_callback);
|
||||
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
/* Init OpenSSL - only required for OpenSSL Versions < 1.1.0 */
|
||||
SSL_library_init();
|
||||
ERR_load_crypto_strings();
|
||||
#endif
|
||||
|
||||
/* Init libssh2 */
|
||||
libssh2_init(0);
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_uninit() {
|
||||
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
|
||||
guac_common_ssh_openssl_free_locks(CRYPTO_num_locks());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the keyboard-interactive authentication method. Currently
|
||||
* supports just one prompt for the password. This callback is invoked as
|
||||
* needed to fullfill a call to libssh2_userauth_keyboard_interactive().
|
||||
*
|
||||
* @param name
|
||||
* An arbitrary name which should be printed to the terminal for the
|
||||
* benefit of the user. This is currently ignored.
|
||||
*
|
||||
* @param name_len
|
||||
* The length of the name string, in bytes.
|
||||
*
|
||||
* @param instruction
|
||||
* Arbitrary instructions which should be printed to the terminal for the
|
||||
* benefit of the user. This is currently ignored.
|
||||
*
|
||||
* @param instruction_len
|
||||
* The length of the instruction string, in bytes.
|
||||
*
|
||||
* @param num_prompts
|
||||
* The number of keyboard-interactive prompts for which responses are
|
||||
* requested. This callback currently only supports one prompt, and assumes
|
||||
* that this prompt is requesting the password.
|
||||
*
|
||||
* @param prompts
|
||||
* An array of all keyboard-interactive prompts for which responses are
|
||||
* requested.
|
||||
*
|
||||
* @param responses
|
||||
* A parallel array into which all prompt responses should be stored. Each
|
||||
* entry within this array corresponds to the entry in the prompts array
|
||||
* with the same index.
|
||||
*
|
||||
* @param abstract
|
||||
* The value of the abstract parameter provided when the SSH session was
|
||||
* created with libssh2_session_init_ex().
|
||||
*/
|
||||
static void guac_common_ssh_kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len, int num_prompts,
|
||||
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
|
||||
void **abstract) {
|
||||
|
||||
guac_common_ssh_session* common_session =
|
||||
(guac_common_ssh_session*) *abstract;
|
||||
|
||||
guac_client* client = common_session->client;
|
||||
|
||||
/* Send password if only one prompt */
|
||||
if (num_prompts == 1) {
|
||||
char* password = common_session->user->password;
|
||||
responses[0].text = strdup(password);
|
||||
responses[0].length = strlen(password);
|
||||
}
|
||||
|
||||
/* If more than one prompt, a single password is not enough */
|
||||
else
|
||||
guac_client_log(client, GUAC_LOG_WARNING,
|
||||
"Unsupported number of keyboard-interactive prompts: %i",
|
||||
num_prompts);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates the user associated with the given session over SSH. All
|
||||
* required credentials must already be present within the user object
|
||||
* associated with the given session.
|
||||
*
|
||||
* @param session
|
||||
* The session associated with the user to be authenticated.
|
||||
*
|
||||
* @return
|
||||
* Zero if authentication succeeds, or non-zero if authentication has
|
||||
* failed.
|
||||
*/
|
||||
static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session) {
|
||||
|
||||
guac_client* client = common_session->client;
|
||||
guac_common_ssh_user* user = common_session->user;
|
||||
LIBSSH2_SESSION* session = common_session->session;
|
||||
|
||||
/* Get user credentials */
|
||||
guac_common_ssh_key* key = user->private_key;
|
||||
|
||||
/* Validate username provided */
|
||||
if (user->username == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"SSH authentication requires a username.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get list of supported authentication methods */
|
||||
size_t username_len = strlen(user->username);
|
||||
char* user_authlist = libssh2_userauth_list(session, user->username,
|
||||
username_len);
|
||||
|
||||
/* If auth list is NULL, then authentication has succeeded with NONE */
|
||||
if (user_authlist == NULL) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"SSH NONE authentication succeeded.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Supported authentication methods: %s", user_authlist);
|
||||
|
||||
/* Authenticate with private key, if provided */
|
||||
if (key != NULL) {
|
||||
|
||||
/* Check if public key auth is supported on the server */
|
||||
if (strstr(user_authlist, "publickey") == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Public key authentication is not supported by "
|
||||
"the SSH server");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Attempt public key auth */
|
||||
if (libssh2_userauth_publickey_frommemory(session, user->username,
|
||||
username_len, NULL, 0, key->private_key,
|
||||
key->private_key_length, key->passphrase)) {
|
||||
|
||||
/* Abort on failure */
|
||||
char* error_message;
|
||||
libssh2_session_last_error(session, &error_message, NULL, 0);
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Public key authentication failed: %s", error_message);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Private key authentication succeeded */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Attempt authentication with username + password. */
|
||||
if (user->password == NULL && common_session->credential_handler)
|
||||
user->password = common_session->credential_handler(client, "Password: ");
|
||||
|
||||
/* Authenticate with password, if provided */
|
||||
if (user->password != NULL) {
|
||||
|
||||
/* Check if password auth is supported on the server */
|
||||
if (strstr(user_authlist, "password") != NULL) {
|
||||
|
||||
/* Attempt password authentication */
|
||||
if (libssh2_userauth_password(session, user->username, user->password)) {
|
||||
|
||||
/* Abort on failure */
|
||||
char* error_message;
|
||||
libssh2_session_last_error(session, &error_message, NULL, 0);
|
||||
guac_client_abort(client,
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Password authentication failed: %s", error_message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Password authentication succeeded */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Check if keyboard-interactive auth is supported on the server */
|
||||
if (strstr(user_authlist, "keyboard-interactive") != NULL) {
|
||||
|
||||
/* Attempt keyboard-interactive auth using provided password */
|
||||
if (libssh2_userauth_keyboard_interactive(session, user->username,
|
||||
&guac_common_ssh_kbd_callback)) {
|
||||
|
||||
/* Abort on failure */
|
||||
char* error_message;
|
||||
libssh2_session_last_error(session, &error_message, NULL, 0);
|
||||
guac_client_abort(client,
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Keyboard-interactive authentication failed: %s",
|
||||
error_message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Keyboard-interactive authentication succeeded */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* No known authentication types available */
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Password and keyboard-interactive authentication are not "
|
||||
"supported by the SSH server");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* No credentials provided */
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"SSH authentication requires either a private key or a password.");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||
const char* hostname, const char* port, guac_common_ssh_user* user,
|
||||
int keepalive, const char* host_key,
|
||||
guac_ssh_credential_handler* credential_handler) {
|
||||
|
||||
int retval;
|
||||
|
||||
int fd;
|
||||
struct addrinfo* addresses;
|
||||
struct addrinfo* current_address;
|
||||
|
||||
char connected_address[1024];
|
||||
char connected_port[64];
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP
|
||||
};
|
||||
|
||||
/* Get addresses connection */
|
||||
if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Error parsing given address or port: %s",
|
||||
gai_strerror(retval));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Attempt connection to each address until success */
|
||||
current_address = addresses;
|
||||
while (current_address != NULL) {
|
||||
|
||||
/* Resolve hostname */
|
||||
if ((retval = getnameinfo(current_address->ai_addr,
|
||||
current_address->ai_addrlen,
|
||||
connected_address, sizeof(connected_address),
|
||||
connected_port, sizeof(connected_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV)))
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Unable to resolve host: %s", gai_strerror(retval));
|
||||
|
||||
/* Get socket */
|
||||
fd = socket(current_address->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Unable to create socket: %s", strerror(errno));
|
||||
freeaddrinfo(addresses);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
if (connect(fd, current_address->ai_addr,
|
||||
current_address->ai_addrlen) == 0) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Successfully connected to host %s, port %s",
|
||||
connected_address, connected_port);
|
||||
|
||||
/* Done if successful connect */
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise log information regarding bind failure */
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to "
|
||||
"host %s, port %s: %s",
|
||||
connected_address, connected_port, strerror(errno));
|
||||
|
||||
close(fd);
|
||||
current_address = current_address->ai_next;
|
||||
|
||||
}
|
||||
|
||||
/* Free addrinfo */
|
||||
freeaddrinfo(addresses);
|
||||
|
||||
/* If unable to connect to anything, fail */
|
||||
if (current_address == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
|
||||
"Unable to connect to any addresses.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate new session */
|
||||
guac_common_ssh_session* common_session =
|
||||
malloc(sizeof(guac_common_ssh_session));
|
||||
|
||||
/* Open SSH session */
|
||||
LIBSSH2_SESSION* session = libssh2_session_init_ex(NULL, NULL,
|
||||
NULL, common_session);
|
||||
if (session == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Session allocation failed.");
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If FIPS mode is enabled, prefer only FIPS-compatible algorithms and
|
||||
* ciphers that are also supported by libssh2. For more info, see:
|
||||
* https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2906.pdf
|
||||
*/
|
||||
if (guac_fips_enabled()) {
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
|
||||
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
|
||||
}
|
||||
|
||||
/* Perform handshake */
|
||||
if (libssh2_session_handshake(session, fd)) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
|
||||
"SSH handshake failed.");
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get host key of remote system we're connecting to */
|
||||
size_t remote_hostkey_len;
|
||||
const char *remote_hostkey = libssh2_session_hostkey(session, &remote_hostkey_len, NULL);
|
||||
|
||||
/* Failure to retrieve a host key means we should abort */
|
||||
if (!remote_hostkey) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Failed to get host key for %s", hostname);
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* SSH known host key checking. */
|
||||
int known_host_check = guac_common_ssh_verify_host_key(session, client, host_key,
|
||||
hostname, atoi(port), remote_hostkey,
|
||||
remote_hostkey_len);
|
||||
|
||||
/* Abort on any error codes */
|
||||
if (known_host_check != 0) {
|
||||
char* err_msg;
|
||||
libssh2_session_last_error(session, &err_msg, NULL, 0);
|
||||
|
||||
if (known_host_check < 0)
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Error occurred attempting to check host key: %s", err_msg);
|
||||
|
||||
if (known_host_check > 0)
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Host key did not match any provided known host keys. %s", err_msg);
|
||||
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Store basic session data */
|
||||
common_session->client = client;
|
||||
common_session->user = user;
|
||||
common_session->session = session;
|
||||
common_session->fd = fd;
|
||||
common_session->credential_handler = credential_handler;
|
||||
|
||||
/* Attempt authentication */
|
||||
if (guac_common_ssh_authenticate(common_session)) {
|
||||
free(common_session);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Warn if keepalive below minimum value */
|
||||
if (keepalive < 0) {
|
||||
keepalive = 0;
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "negative keepalive intervals "
|
||||
"are converted to 0, disabling keepalive.");
|
||||
}
|
||||
else if (keepalive == 1) {
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "keepalive interval will "
|
||||
"be rounded up to minimum value of 2.");
|
||||
}
|
||||
|
||||
/* Configure session keepalive */
|
||||
libssh2_keepalive_config(common_session->session, 1, keepalive);
|
||||
|
||||
/* Return created session */
|
||||
return common_session;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_destroy_session(guac_common_ssh_session* session) {
|
||||
|
||||
/* Disconnect and clean up libssh2 */
|
||||
libssh2_session_disconnect(session->session, "Bye");
|
||||
libssh2_session_free(session->session);
|
||||
|
||||
/* Free all other data */
|
||||
free(session);
|
||||
|
||||
}
|
67
src/common-ssh/tests/Makefile.am
Normal file
67
src/common-ssh/tests/Makefile.am
Normal file
@ -0,0 +1,67 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
#
|
||||
# Unit tests for common SSH support
|
||||
#
|
||||
|
||||
check_PROGRAMS = test_common_ssh
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
test_common_ssh_SOURCES = \
|
||||
sftp/normalize_path.c
|
||||
|
||||
test_common_ssh_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
test_common_ssh_LDADD = \
|
||||
@CUNIT_LIBS@ \
|
||||
@COMMON_SSH_LTLIB@ \
|
||||
@COMMON_LTLIB@
|
||||
|
||||
#
|
||||
# Autogenerate test runner
|
||||
#
|
||||
|
||||
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_common_ssh_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_common_ssh_SOURCES) > $@
|
||||
|
||||
nodist_test_common_ssh_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
||||
# Use automake's TAP test driver for running any tests
|
||||
LOG_DRIVER = \
|
||||
env AM_TAP_AWK='$(AWK)' \
|
||||
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
|
||||
|
263
src/common-ssh/tests/sftp/normalize_path.c
Normal file
263
src/common-ssh/tests/sftp/normalize_path.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common-ssh/sftp.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Test which verifies absolute Windows-style paths are correctly normalized to
|
||||
* absolute paths with UNIX separators and no relative components.
|
||||
*/
|
||||
void test_sftp__normalize_absolute_windows() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\baz\\"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\baz\\a\\..\\b"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar\\baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\..\\..\\..\\..\\baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies absolute UNIX-style paths are correctly normalized to
|
||||
* absolute paths with UNIX separators and no relative components.
|
||||
*/
|
||||
void test_sftp__normalize_absolute_unix() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../baz/"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../baz/a/../b"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/./bar/baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../../../../../baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies absolute paths consisting of mixed Windows and UNIX path
|
||||
* separators are correctly normalized to absolute paths with UNIX separators
|
||||
* and no relative components.
|
||||
*/
|
||||
void test_sftp__normalize_absolute_mixed() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo\\bar/..\\baz/"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../../baz\\a\\..\\b"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar/baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../..\\..\\..\\../..\\baz"), 0);
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative Windows-style paths are always rejected.
|
||||
*/
|
||||
void test_sftp__normalize_relative_windows() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar\\baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo\\bar\\baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo\\bar\\baz"), 0);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative UNIX-style paths are always rejected.
|
||||
*/
|
||||
void test_sftp__normalize_relative_unix() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo/bar/baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo/bar/baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo/bar/baz"), 0);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative paths consisting of mixed Windows and UNIX path
|
||||
* separators are always rejected.
|
||||
*/
|
||||
void test_sftp__normalize_relative_mixed() {
|
||||
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar/baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo/bar/baz"), 0);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo\\bar\\baz"), 0);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dynamically-allocated path having the given number of bytes, not
|
||||
* counting the null-terminator. The path will contain only UNIX-style path
|
||||
* separators. The returned path must eventually be freed with a call to
|
||||
* free().
|
||||
*
|
||||
* @param length
|
||||
* The number of bytes to include in the generated path, not counting the
|
||||
* null-terminator. If -1, the length of the path will be automatically
|
||||
* determined from the provided max_depth.
|
||||
*
|
||||
* @param max_depth
|
||||
* The maximum number of path components to include within the generated
|
||||
* path.
|
||||
*
|
||||
* @return
|
||||
* A dynamically-allocated path containing the given number of bytes, not
|
||||
* counting the null-terminator. This path must eventually be freed with a
|
||||
* call to free().
|
||||
*/
|
||||
static char* generate_path(int length, int max_depth) {
|
||||
|
||||
/* If no length given, calculate space required from max_depth */
|
||||
if (length == -1)
|
||||
length = max_depth * 2;
|
||||
|
||||
int i;
|
||||
char* input = malloc(length + 1);
|
||||
|
||||
/* Fill path with /x/x/x/x/x/x/x/x/x/x/.../xxxxxxxxx... */
|
||||
for (i = 0; i < length; i++) {
|
||||
if (max_depth > 0 && i % 2 == 0) {
|
||||
input[i] = '/';
|
||||
max_depth--;
|
||||
}
|
||||
else
|
||||
input[i] = 'x';
|
||||
}
|
||||
|
||||
/* Add null terminator */
|
||||
input[length] = '\0';
|
||||
|
||||
return input;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that paths exceeding the maximum path length are
|
||||
* rejected.
|
||||
*/
|
||||
void test_sftp__normalize_long() {
|
||||
|
||||
char* input;
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
/* Exceeds maximum length by a factor of 2 */
|
||||
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH * 2, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
/* Exceeds maximum length by one byte */
|
||||
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
/* Exactly maximum length */
|
||||
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH - 1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that paths exceeding the maximum path depth are
|
||||
* rejected.
|
||||
*/
|
||||
void test_sftp__normalize_deep() {
|
||||
|
||||
char* input;
|
||||
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
|
||||
|
||||
/* Exceeds maximum depth by a factor of 2 */
|
||||
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH * 2);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
/* Exceeds maximum depth by one component */
|
||||
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH + 1);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
/* Exactly maximum depth (should still be rejected as SFTP depth limits are
|
||||
* set such that a path with the maximum depth will exceed the maximum
|
||||
* length) */
|
||||
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
|
||||
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
/* Less than maximum depth */
|
||||
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH - 1);
|
||||
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
|
||||
free(input);
|
||||
|
||||
}
|
||||
|
82
src/common-ssh/user.c
Normal file
82
src/common-ssh/user.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common-ssh/key.h"
|
||||
#include "common-ssh/user.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
guac_common_ssh_user* guac_common_ssh_create_user(const char* username) {
|
||||
|
||||
guac_common_ssh_user* user = malloc(sizeof(guac_common_ssh_user));
|
||||
|
||||
/* Init user */
|
||||
user->username = strdup(username);
|
||||
user->password = NULL;
|
||||
user->private_key = NULL;
|
||||
|
||||
return user;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_destroy_user(guac_common_ssh_user* user) {
|
||||
|
||||
/* Free private key, if present */
|
||||
if (user->private_key != NULL)
|
||||
guac_common_ssh_key_free(user->private_key);
|
||||
|
||||
/* Free all other data */
|
||||
free(user->password);
|
||||
free(user->username);
|
||||
free(user);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_ssh_user_set_password(guac_common_ssh_user* user,
|
||||
const char* password) {
|
||||
|
||||
/* Replace current password with given value */
|
||||
free(user->password);
|
||||
user->password = strdup(password);
|
||||
|
||||
}
|
||||
|
||||
int guac_common_ssh_user_import_key(guac_common_ssh_user* user,
|
||||
char* private_key, char* passphrase) {
|
||||
|
||||
/* Free existing private key, if present */
|
||||
if (user->private_key != NULL)
|
||||
guac_common_ssh_key_free(user->private_key);
|
||||
|
||||
/* Attempt to read key without passphrase if none given */
|
||||
if (passphrase == NULL)
|
||||
user->private_key = guac_common_ssh_key_alloc(private_key,
|
||||
strlen(private_key), "");
|
||||
|
||||
/* Otherwise, use provided passphrase */
|
||||
else
|
||||
user->private_key = guac_common_ssh_key_alloc(private_key,
|
||||
strlen(private_key), passphrase);
|
||||
|
||||
/* Fail if key could not be read */
|
||||
return user->private_key == NULL;
|
||||
|
||||
}
|
||||
|
5
src/common/.gitignore
vendored
Normal file
5
src/common/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# Auto-generated test runner and binary
|
||||
_generated_runner.c
|
||||
test_common
|
||||
|
@ -1,52 +1,71 @@
|
||||
#
|
||||
# Copyright (C) 2013 Glyptodon LLC
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@
|
||||
|
||||
noinst_LTLIBRARIES = libguac_common.la
|
||||
SUBDIRS = . tests
|
||||
|
||||
noinst_HEADERS = \
|
||||
guac_io.h \
|
||||
guac_clipboard.h \
|
||||
guac_dot_cursor.h \
|
||||
guac_iconv.h \
|
||||
guac_list.h \
|
||||
guac_pointer_cursor.h \
|
||||
guac_rect.h \
|
||||
guac_string.h \
|
||||
guac_surface.h
|
||||
noinst_HEADERS = \
|
||||
common/io.h \
|
||||
common/blank_cursor.h \
|
||||
common/clipboard.h \
|
||||
common/cursor.h \
|
||||
common/defaults.h \
|
||||
common/display.h \
|
||||
common/dot_cursor.h \
|
||||
common/ibar_cursor.h \
|
||||
common/iconv.h \
|
||||
common/json.h \
|
||||
common/list.h \
|
||||
common/pointer_cursor.h \
|
||||
common/rect.h \
|
||||
common/string.h \
|
||||
common/surface.h
|
||||
|
||||
libguac_common_la_SOURCES = \
|
||||
guac_io.c \
|
||||
guac_clipboard.c \
|
||||
guac_dot_cursor.c \
|
||||
guac_iconv.c \
|
||||
guac_list.c \
|
||||
guac_pointer_cursor.c \
|
||||
guac_rect.c \
|
||||
guac_string.c \
|
||||
guac_surface.c
|
||||
io.c \
|
||||
blank_cursor.c \
|
||||
clipboard.c \
|
||||
cursor.c \
|
||||
display.c \
|
||||
dot_cursor.c \
|
||||
ibar_cursor.c \
|
||||
iconv.c \
|
||||
json.c \
|
||||
list.c \
|
||||
pointer_cursor.c \
|
||||
rect.c \
|
||||
string.c \
|
||||
surface.c
|
||||
|
||||
libguac_common_la_LIBADD = @LIBGUAC_LTLIB@
|
||||
libguac_common_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
libguac_common_la_LIBADD = \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
|
75
src/common/blank_cursor.c
Normal file
75
src/common/blank_cursor.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Dimensions */
|
||||
const int guac_common_blank_cursor_width = 1;
|
||||
const int guac_common_blank_cursor_height = 1;
|
||||
|
||||
/* Format */
|
||||
const cairo_format_t guac_common_blank_cursor_format = CAIRO_FORMAT_ARGB32;
|
||||
const int guac_common_blank_cursor_stride = 4;
|
||||
|
||||
/* Embedded blank cursor graphic */
|
||||
unsigned char guac_common_blank_cursor[] = {
|
||||
|
||||
0x00,0x00,0x00,0x00
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_blank_cursor(guac_user* user) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
|
||||
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
|
||||
guac_common_blank_cursor,
|
||||
guac_common_blank_cursor_format,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height,
|
||||
guac_common_blank_cursor_stride);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
guac_protocol_send_cursor(socket, 0, 0, cursor, 0, 0,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height);
|
||||
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic transparent (blank) cursor.");
|
||||
|
||||
}
|
||||
|
166
src/common/clipboard.c
Normal file
166
src/common/clipboard.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/clipboard.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
guac_common_clipboard* guac_common_clipboard_alloc() {
|
||||
|
||||
guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard));
|
||||
|
||||
/* Init clipboard */
|
||||
clipboard->mimetype[0] = '\0';
|
||||
clipboard->buffer = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
|
||||
clipboard->available = GUAC_COMMON_CLIPBOARD_MAX_LENGTH;
|
||||
clipboard->length = 0;
|
||||
|
||||
pthread_mutex_init(&(clipboard->lock), NULL);
|
||||
|
||||
return clipboard;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_free(guac_common_clipboard* clipboard) {
|
||||
|
||||
/* Destroy lock */
|
||||
pthread_mutex_destroy(&(clipboard->lock));
|
||||
|
||||
/* Free buffer */
|
||||
free(clipboard->buffer);
|
||||
|
||||
/* Free base structure */
|
||||
free(clipboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for guac_client_foreach_user() which sends clipboard data to each
|
||||
* connected client.
|
||||
*
|
||||
* @param user
|
||||
* The user to send the clipboard data to.
|
||||
*
|
||||
* @param
|
||||
* A pointer to the guac_common_clipboard structure containing the
|
||||
* clipboard data that should be sent to the given user.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
static void* __send_user_clipboard(guac_user* user, void* data) {
|
||||
|
||||
guac_common_clipboard* clipboard = (guac_common_clipboard*) data;
|
||||
|
||||
char* current = clipboard->buffer;
|
||||
int remaining = clipboard->length;
|
||||
|
||||
/* Begin stream */
|
||||
guac_stream* stream = guac_user_alloc_stream(user);
|
||||
guac_protocol_send_clipboard(user->socket, stream, clipboard->mimetype);
|
||||
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Created stream %i for %s clipboard data.",
|
||||
stream->index, clipboard->mimetype);
|
||||
|
||||
/* Split clipboard into chunks */
|
||||
while (remaining > 0) {
|
||||
|
||||
/* Calculate size of next block */
|
||||
int block_size = GUAC_COMMON_CLIPBOARD_BLOCK_SIZE;
|
||||
if (remaining < block_size)
|
||||
block_size = remaining;
|
||||
|
||||
/* Send block */
|
||||
guac_protocol_send_blob(user->socket, stream, current, block_size);
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Sent %i bytes of clipboard data on stream %i.",
|
||||
block_size, stream->index);
|
||||
|
||||
/* Next block */
|
||||
remaining -= block_size;
|
||||
current += block_size;
|
||||
|
||||
}
|
||||
|
||||
guac_user_log(user, GUAC_LOG_DEBUG,
|
||||
"Clipboard stream %i complete.",
|
||||
stream->index);
|
||||
|
||||
/* End stream */
|
||||
guac_protocol_send_end(user->socket, stream);
|
||||
guac_user_free_stream(user, stream);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcasting clipboard to all connected users.");
|
||||
guac_client_foreach_user(client, __send_user_clipboard, clipboard);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcast of clipboard complete.");
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_reset(guac_common_clipboard* clipboard,
|
||||
const char* mimetype) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
/* Clear clipboard contents */
|
||||
clipboard->length = 0;
|
||||
|
||||
/* Assign given mimetype */
|
||||
guac_strlcpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype));
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length) {
|
||||
|
||||
pthread_mutex_lock(&(clipboard->lock));
|
||||
|
||||
/* Truncate data to available length */
|
||||
int remaining = clipboard->available - clipboard->length;
|
||||
if (remaining < length)
|
||||
length = remaining;
|
||||
|
||||
/* Append to buffer */
|
||||
memcpy(clipboard->buffer + clipboard->length, data, length);
|
||||
|
||||
/* Update length */
|
||||
clipboard->length += length;
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
}
|
||||
|
64
src/common/common/blank_cursor.h
Normal file
64
src/common/common/blank_cursor.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_BLANK_CURSOR_H
|
||||
#define GUAC_COMMON_BLANK_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded transparent (blank) mouse cursor
|
||||
* graphic.
|
||||
*/
|
||||
extern const int guac_common_blank_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_blank_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded transparent (blank) mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_blank_cursor[];
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded transparent (blank)
|
||||
* cursor graphic.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_blank_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
@ -1,23 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_CLIPBOARD_H
|
||||
@ -26,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to send in an individual blob when
|
||||
@ -33,11 +31,23 @@
|
||||
*/
|
||||
#define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#define GUAC_COMMON_CLIPBOARD_MAX_LENGTH 262144
|
||||
|
||||
/**
|
||||
* Generic clipboard structure.
|
||||
*/
|
||||
typedef struct guac_common_clipboard {
|
||||
|
||||
/**
|
||||
* Lock which restricts simultaneous access to the clipboard, guaranteeing
|
||||
* ordered modifications to the clipboard and that changes to the clipboard
|
||||
* are not allowed while the clipboard is being broadcast to all users.
|
||||
*/
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/**
|
||||
* The mimetype of the contained clipboard data.
|
||||
*/
|
||||
@ -61,12 +71,9 @@ typedef struct guac_common_clipboard {
|
||||
} guac_common_clipboard;
|
||||
|
||||
/**
|
||||
* Creates a new clipboard having the given initial size.
|
||||
*
|
||||
* @param size The maximum number of bytes to allow within the clipboard.
|
||||
* @return A newly-allocated clipboard.
|
||||
* Creates a new clipboard.
|
||||
*/
|
||||
guac_common_clipboard* guac_common_clipboard_alloc(int size);
|
||||
guac_common_clipboard* guac_common_clipboard_alloc();
|
||||
|
||||
/**
|
||||
* Frees the given clipboard.
|
300
src/common/common/cursor.h
Normal file
300
src/common/common/cursor.h
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_COMMON_CURSOR_H
|
||||
#define GUAC_COMMON_CURSOR_H
|
||||
|
||||
#include "surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The default size of the cursor image buffer.
|
||||
*/
|
||||
#define GUAC_COMMON_CURSOR_DEFAULT_SIZE 64*64*4
|
||||
|
||||
/**
|
||||
* Cursor object which maintains and synchronizes the current mouse cursor
|
||||
* state across all users of a specific client.
|
||||
*/
|
||||
typedef struct guac_common_cursor {
|
||||
|
||||
/**
|
||||
* The client to maintain the mouse cursor for.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The buffer containing the current cursor image.
|
||||
*/
|
||||
guac_layer* buffer;
|
||||
|
||||
/**
|
||||
* The width of the cursor image, in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the cursor image, in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* Arbitrary image data buffer, backing the Cairo surface used to store
|
||||
* the cursor image.
|
||||
*/
|
||||
unsigned char* image_buffer;
|
||||
|
||||
/**
|
||||
* The size of the image data buffer, in bytes.
|
||||
*/
|
||||
int image_buffer_size;
|
||||
|
||||
/**
|
||||
* The current cursor image, if any. If the mouse cursor has not yet been
|
||||
* set, this will be NULL.
|
||||
*/
|
||||
cairo_surface_t* surface;
|
||||
|
||||
/**
|
||||
* The X coordinate of the hotspot of the mouse cursor.
|
||||
*/
|
||||
int hotspot_x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the hotspot of the mouse cursor.
|
||||
*/
|
||||
int hotspot_y;
|
||||
|
||||
/**
|
||||
* The last user to move the mouse, or NULL if no user has moved the
|
||||
* mouse yet.
|
||||
*/
|
||||
guac_user* user;
|
||||
|
||||
/**
|
||||
* The X coordinate of the current mouse cursor location.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the current mouse cursor location.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* An integer value representing the current state of each button, where
|
||||
* the Nth bit within the integer is set to 1 if and only if the Nth mouse
|
||||
* button is currently pressed. The lowest-order bit is the left mouse
|
||||
* button, followed by the middle button, right button, and finally the up
|
||||
* and down buttons of the scroll wheel.
|
||||
*
|
||||
* @see GUAC_CLIENT_MOUSE_LEFT
|
||||
* @see GUAC_CLIENT_MOUSE_MIDDLE
|
||||
* @see GUAC_CLIENT_MOUSE_RIGHT
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
|
||||
*/
|
||||
int button_mask;
|
||||
|
||||
/**
|
||||
* The server timestamp representing the point in time when the mousr
|
||||
* location was last updated.
|
||||
*/
|
||||
guac_timestamp timestamp;
|
||||
|
||||
} guac_common_cursor;
|
||||
|
||||
/**
|
||||
* Allocates a new cursor object which maintains and synchronizes the current
|
||||
* mouse cursor state across all users of the given client.
|
||||
*
|
||||
* @param client
|
||||
* The client for which this object shall maintain the mouse cursor.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated mouse cursor.
|
||||
*/
|
||||
guac_common_cursor* guac_common_cursor_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Frees the given cursor.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to free.
|
||||
*/
|
||||
void guac_common_cursor_free(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sends the current state of this cursor across the given socket, including
|
||||
* the current cursor image. The resulting cursor on the remote display will
|
||||
* be visible.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to send.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the updated cursor.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the updated cursor should be sent.
|
||||
*/
|
||||
void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Updates the current position and button state of the mouse cursor, marking
|
||||
* the given user as the most recent user of the mouse. The remote mouse cursor
|
||||
* will be hidden for this user and shown for all others.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor being updated.
|
||||
*
|
||||
* @param user
|
||||
* The user that moved the cursor.
|
||||
*
|
||||
* @param x
|
||||
* The new X coordinate of the cursor.
|
||||
*
|
||||
* @param y
|
||||
* The new Y coordinate of the cursor.
|
||||
*
|
||||
* @param button_mask
|
||||
* An integer value representing the current state of each button, where
|
||||
* the Nth bit within the integer is set to 1 if and only if the Nth mouse
|
||||
* button is currently pressed. The lowest-order bit is the left mouse
|
||||
* button, followed by the middle button, right button, and finally the up
|
||||
* and down buttons of the scroll wheel.
|
||||
*
|
||||
* @see GUAC_CLIENT_MOUSE_LEFT
|
||||
* @see GUAC_CLIENT_MOUSE_MIDDLE
|
||||
* @see GUAC_CLIENT_MOUSE_RIGHT
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
|
||||
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
|
||||
*/
|
||||
void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user,
|
||||
int x, int y, int button_mask);
|
||||
|
||||
/**
|
||||
* Sets the cursor image to the given raw image data. This raw image data must
|
||||
* be in 32-bit ARGB format, having 8 bits per color component, where the
|
||||
* alpha component is stored in the high-order 8 bits, and blue is stored
|
||||
* in the low-order 8 bits.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*
|
||||
* @param hx
|
||||
* The X coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param hy
|
||||
* The Y coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to raw 32-bit ARGB image data.
|
||||
*
|
||||
* @param width
|
||||
* The width of the given image data, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the given image data, in pixels.
|
||||
*
|
||||
* @param stride
|
||||
* The number of bytes in a single row of image data.
|
||||
*/
|
||||
void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy,
|
||||
unsigned const char* data, int width, int height, int stride);
|
||||
|
||||
/**
|
||||
* Sets the cursor image to the contents of the given surface. The entire
|
||||
* contents of the surface are used, and the dimensions of the resulting
|
||||
* cursor will be the dimensions of the given surface.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*
|
||||
* @param hx
|
||||
* The X coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param hy
|
||||
* The Y coordinate of the hotspot of the new cursor image.
|
||||
*
|
||||
* @param surface
|
||||
* The surface containing the cursor image.
|
||||
*/
|
||||
void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy,
|
||||
guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded "pointer" graphic. The
|
||||
* pointer graphic is a black arrow with white border.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_pointer(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded "dot" graphic. The dot
|
||||
* graphic is a small black square with white border.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_dot(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded "I-bar" graphic. The
|
||||
* I-bar graphic is a small black "I" shape with white border, used to indicate
|
||||
* the presence of selectable or editable text.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_ibar(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded transparent (blank)
|
||||
* graphic, effectively hiding the mouse cursor.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to set the image of.
|
||||
*/
|
||||
void guac_common_cursor_set_blank(guac_common_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Removes the given user, such that future synchronization will not occur.
|
||||
* This is necessary when a user leaves the connection. If a user leaves the
|
||||
* connection and this is not called, the mouse cursor state may not update
|
||||
* correctly in response to mouse events.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor to remove the user from.
|
||||
*
|
||||
* @param user
|
||||
* The user to remove.
|
||||
*/
|
||||
void guac_common_cursor_remove_user(guac_common_cursor* cursor,
|
||||
guac_user* user);
|
||||
|
||||
#endif
|
31
src/common/common/defaults.h
Normal file
31
src/common/common/defaults.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_DEFAULTS_H
|
||||
#define GUAC_COMMON_DEFAULTS_H
|
||||
|
||||
/**
|
||||
* The default number of seconds to wait after sending the Wake-on-LAN packet
|
||||
* for the destination host to start responding.
|
||||
*/
|
||||
#define GUAC_WOL_DEFAULT_BOOT_WAIT_TIME 0
|
||||
|
||||
|
||||
#endif /* GUAC_COMMON_DEFAULTS_H */
|
||||
|
261
src/common/common/display.h
Normal file
261
src/common/common/display.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_DISPLAY_H
|
||||
#define GUAC_COMMON_DISPLAY_H
|
||||
|
||||
#include "cursor.h"
|
||||
#include "surface.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* A list element representing a pairing of a Guacamole layer with a
|
||||
* corresponding guac_common_surface which wraps that layer. Adjacent layers
|
||||
* within the same list are pointed to with traditional prev/next pointers. The
|
||||
* order of layers in lists need not correspond in any way to the natural
|
||||
* ordering of those layers' indexes nor their stacking order (Z-order) within
|
||||
* the display.
|
||||
*/
|
||||
typedef struct guac_common_display_layer guac_common_display_layer;
|
||||
|
||||
struct guac_common_display_layer {
|
||||
|
||||
/**
|
||||
* A Guacamole layer.
|
||||
*/
|
||||
guac_layer* layer;
|
||||
|
||||
/**
|
||||
* The surface which wraps the associated layer.
|
||||
*/
|
||||
guac_common_surface* surface;
|
||||
|
||||
/**
|
||||
* The layer immediately prior to this layer within the list containing
|
||||
* this layer, or NULL if this is the first layer/buffer in the list.
|
||||
*/
|
||||
guac_common_display_layer* prev;
|
||||
|
||||
/**
|
||||
* The layer immediately following this layer within the list containing
|
||||
* this layer, or NULL if this is the last layer/buffer in the list.
|
||||
*/
|
||||
guac_common_display_layer* next;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstracts a remote Guacamole display, having an associated client,
|
||||
* default surface, mouse cursor, and various allocated buffers and layers.
|
||||
*/
|
||||
typedef struct guac_common_display {
|
||||
|
||||
/**
|
||||
* The client associate with this display.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The default surface of the client display.
|
||||
*/
|
||||
guac_common_surface* default_surface;
|
||||
|
||||
/**
|
||||
* Client-wide cursor, synchronized across all users.
|
||||
*/
|
||||
guac_common_cursor* cursor;
|
||||
|
||||
/**
|
||||
* The first element within a linked list of all currently-allocated
|
||||
* layers, or NULL if no layers are currently allocated. The default layer,
|
||||
* layer #0, is stored within default_surface and will not have a
|
||||
* corresponding element within this list.
|
||||
*/
|
||||
guac_common_display_layer* layers;
|
||||
|
||||
/**
|
||||
* The first element within a linked list of all currently-allocated
|
||||
* buffers, or NULL if no buffers are currently allocated.
|
||||
*/
|
||||
guac_common_display_layer* buffers;
|
||||
|
||||
/**
|
||||
* Non-zero if all graphical updates for this display should use lossless
|
||||
* compression, 0 otherwise. By default, newly-created displays will use
|
||||
* lossy compression when heuristics determine it is appropriate.
|
||||
*/
|
||||
int lossless;
|
||||
|
||||
/**
|
||||
* Mutex which is locked internally when access to the display must be
|
||||
* synchronized. All public functions of guac_common_display should be
|
||||
* considered threadsafe.
|
||||
*/
|
||||
pthread_mutex_t _lock;
|
||||
|
||||
} guac_common_display;
|
||||
|
||||
/**
|
||||
* Allocates a new display, abstracting the cursor and buffer/layer allocation
|
||||
* operations of the given guac_client such that client state can be easily
|
||||
* synchronized to joining users.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client to associate with this display.
|
||||
*
|
||||
* @param width
|
||||
* The initial width of the display, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The initial height of the display, in pixels.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated display.
|
||||
*/
|
||||
guac_common_display* guac_common_display_alloc(guac_client* client,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Frees the given display, and any associated resources, including any
|
||||
* allocated buffers/layers.
|
||||
*
|
||||
* @param display
|
||||
* The display to free.
|
||||
*/
|
||||
void guac_common_display_free(guac_common_display* display);
|
||||
|
||||
/**
|
||||
* Duplicates the state of the given display to the given socket. Any pending
|
||||
* changes to buffers, layers, or the default layer are not flushed.
|
||||
*
|
||||
* @param display
|
||||
* The display whose state should be sent along the given socket.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the display state.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the display state should be sent.
|
||||
*/
|
||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Flushes pending changes to the given display. All pending operations will
|
||||
* become visible to any connected users.
|
||||
*
|
||||
* @param display
|
||||
* The display to flush.
|
||||
*/
|
||||
void guac_common_display_flush(guac_common_display* display);
|
||||
|
||||
/**
|
||||
* Allocates a new layer, returning a new wrapped layer and corresponding
|
||||
* surface. The layer may be reused from a previous allocation, if that layer
|
||||
* has since been freed.
|
||||
*
|
||||
* @param display
|
||||
* The display to allocate a new layer from.
|
||||
*
|
||||
* @param width
|
||||
* The width of the layer to allocate, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the layer to allocate, in pixels.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated layer.
|
||||
*/
|
||||
guac_common_display_layer* guac_common_display_alloc_layer(
|
||||
guac_common_display* display, int width, int height);
|
||||
|
||||
/**
|
||||
* Allocates a new buffer, returning a new wrapped buffer and corresponding
|
||||
* surface. The buffer may be reused from a previous allocation, if that buffer
|
||||
* has since been freed.
|
||||
*
|
||||
* @param display
|
||||
* The display to allocate a new buffer from.
|
||||
*
|
||||
* @param width
|
||||
* The width of the buffer to allocate, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The height of the buffer to allocate, in pixels.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated buffer.
|
||||
*/
|
||||
guac_common_display_layer* guac_common_display_alloc_buffer(
|
||||
guac_common_display* display, int width, int height);
|
||||
|
||||
/**
|
||||
* Frees the given surface and associated layer, returning the layer to the
|
||||
* given display for future use.
|
||||
*
|
||||
* @param display
|
||||
* The display originally allocating the layer.
|
||||
*
|
||||
* @param display_layer
|
||||
* The layer to free.
|
||||
*/
|
||||
void guac_common_display_free_layer(guac_common_display* display,
|
||||
guac_common_display_layer* display_layer);
|
||||
|
||||
/**
|
||||
* Frees the given surface and associated buffer, returning the buffer to the
|
||||
* given display for future use.
|
||||
*
|
||||
* @param display
|
||||
* The display originally allocating the buffer.
|
||||
*
|
||||
* @param display_buffer
|
||||
* The buffer to free.
|
||||
*/
|
||||
void guac_common_display_free_buffer(guac_common_display* display,
|
||||
guac_common_display_layer* display_buffer);
|
||||
|
||||
/**
|
||||
* Sets the overall lossless compression policy of the given display to the
|
||||
* given value, affecting all current and future layers/buffers maintained by
|
||||
* the display. By default, newly-created displays will use lossy compression
|
||||
* for graphical updates when heuristics determine that doing so is
|
||||
* appropriate. Specifying a non-zero value here will force all graphical
|
||||
* updates to always use lossless compression, whereas specifying zero will
|
||||
* restore the default policy.
|
||||
*
|
||||
* Note that this can also be adjusted on a per-layer / per-buffer basis with
|
||||
* guac_common_surface_set_lossless().
|
||||
*
|
||||
* @param display
|
||||
* The display to modify.
|
||||
*
|
||||
* @param lossless
|
||||
* Non-zero if all graphical updates for this display should use lossless
|
||||
* compression, 0 otherwise.
|
||||
*/
|
||||
void guac_common_display_set_lossless(guac_common_display* display,
|
||||
int lossless);
|
||||
|
||||
#endif
|
||||
|
61
src/common/common/dot_cursor.h
Normal file
61
src/common/common/dot_cursor.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUAC_COMMON_DOT_CURSOR_H
|
||||
#define _GUAC_COMMON_DOT_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_dot_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_dot_cursor[];
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param user The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_dot_cursor(guac_user* user);
|
||||
|
||||
#endif
|
62
src/common/common/ibar_cursor.h
Normal file
62
src/common/common/ibar_cursor.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_IBAR_CURSOR_H
|
||||
#define GUAC_COMMON_IBAR_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_ibar_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_ibar_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded I-bar mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_ibar_cursor[];
|
||||
|
||||
/**
|
||||
* Sets the cursor of the remote display to the embedded I-bar cursor graphic.
|
||||
*
|
||||
* @param user
|
||||
* The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_ibar_cursor(guac_user* user);
|
||||
|
||||
#endif
|
||||
|
@ -1,23 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_ICONV_H
|
||||
@ -79,6 +76,30 @@ guac_iconv_read GUAC_READ_CP1252;
|
||||
*/
|
||||
guac_iconv_read GUAC_READ_ISO8859_1;
|
||||
|
||||
/**
|
||||
* Read function for UTF-8 which normalizes newline character sequences like
|
||||
* "\r\n" to Unix-style newlines ('\n').
|
||||
*/
|
||||
guac_iconv_read GUAC_READ_UTF8_NORMALIZED;
|
||||
|
||||
/**
|
||||
* Read function for UTF-16 which normalizes newline character sequences like
|
||||
* "\r\n" to Unix-style newlines ('\n').
|
||||
*/
|
||||
guac_iconv_read GUAC_READ_UTF16_NORMALIZED;
|
||||
|
||||
/**
|
||||
* Read function for CP-1252 which normalizes newline character sequences like
|
||||
* "\r\n" to Unix-style newlines ('\n').
|
||||
*/
|
||||
guac_iconv_read GUAC_READ_CP1252_NORMALIZED;
|
||||
|
||||
/**
|
||||
* Read function for ISO 8859-1 which normalizes newline character sequences
|
||||
* like "\r\n" to Unix-style newlines ('\n').
|
||||
*/
|
||||
guac_iconv_read GUAC_READ_ISO8859_1_NORMALIZED;
|
||||
|
||||
/**
|
||||
* Write function for UTF8.
|
||||
*/
|
||||
@ -99,5 +120,29 @@ guac_iconv_write GUAC_WRITE_CP1252;
|
||||
*/
|
||||
guac_iconv_write GUAC_WRITE_ISO8859_1;
|
||||
|
||||
/**
|
||||
* Write function for UTF-8 which writes newline characters ('\n') as
|
||||
* Windows-style newlines ("\r\n").
|
||||
*/
|
||||
guac_iconv_write GUAC_WRITE_UTF8_CRLF;
|
||||
|
||||
/**
|
||||
* Write function for UTF-16 which writes newline characters ('\n') as
|
||||
* Windows-style newlines ("\r\n").
|
||||
*/
|
||||
guac_iconv_write GUAC_WRITE_UTF16_CRLF;
|
||||
|
||||
/**
|
||||
* Write function for CP-1252 which writes newline characters ('\n') as
|
||||
* Windows-style newlines ("\r\n").
|
||||
*/
|
||||
guac_iconv_write GUAC_WRITE_CP1252_CRLF;
|
||||
|
||||
/**
|
||||
* Write function for ISO 8859-1 which writes newline characters ('\n') as
|
||||
* Windows-style newlines ("\r\n").
|
||||
*/
|
||||
guac_iconv_write GUAC_WRITE_ISO8859_1_CRLF;
|
||||
|
||||
#endif
|
||||
|
50
src/common/common/io.h
Normal file
50
src/common/common/io.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_IO_H
|
||||
#define __GUAC_COMMON_IO_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Writes absolutely all bytes from within the given buffer, returning an error
|
||||
* only if the required writes fail.
|
||||
*
|
||||
* @param fd The file descriptor to write to.
|
||||
* @param buffer The buffer containing the data to write.
|
||||
* @param length The number of bytes to write.
|
||||
* @return The number of bytes written, or a value less than zero if an error
|
||||
* occurs.
|
||||
*/
|
||||
int guac_common_write(int fd, void* buffer, int length);
|
||||
|
||||
/**
|
||||
* Reads enough bytes to fill the given buffer, returning an error only if the
|
||||
* required reads fail.
|
||||
*
|
||||
* @param fd The file descriptor to read from.
|
||||
* @param buffer The buffer to read data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return The number of bytes read, or a value less than zero if an error
|
||||
* occurs.
|
||||
*/
|
||||
int guac_common_read(int fd, void* buffer, int length);
|
||||
|
||||
#endif
|
||||
|
196
src/common/common/json.h
Normal file
196
src/common/common/json.h
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_COMMON_JSON_H
|
||||
#define GUAC_COMMON_JSON_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* The current streaming state of an arbitrary JSON object, consisting of
|
||||
* any number of property name/value pairs.
|
||||
*/
|
||||
typedef struct guac_common_json_state {
|
||||
|
||||
/**
|
||||
* Buffer of partial JSON data. The individual blobs which make up the JSON
|
||||
* body of the object being sent over the Guacamole protocol will be
|
||||
* built here.
|
||||
*/
|
||||
char buffer[4096];
|
||||
|
||||
/**
|
||||
* The number of bytes currently used within the JSON buffer.
|
||||
*/
|
||||
int size;
|
||||
|
||||
/**
|
||||
* The number of property name/value pairs written to the JSON object thus
|
||||
* far.
|
||||
*/
|
||||
int properties_written;
|
||||
|
||||
} guac_common_json_state;
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, flushes the contents of the JSON buffer to a blob
|
||||
* instruction. Note that this will flush the JSON buffer only, and will not
|
||||
* necessarily flush the underlying guac_socket of the user.
|
||||
*
|
||||
* @param user
|
||||
* The user to which the data will be flushed.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object whose buffer should be flushed.
|
||||
*/
|
||||
void guac_common_json_flush(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, writes the contents of the given buffer to the JSON buffer
|
||||
* of the stream state, flushing as necessary.
|
||||
*
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
* data must be flushed at all.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object containing the JSON buffer to which the given buffer
|
||||
* should be written.
|
||||
*
|
||||
* @param buffer
|
||||
* The buffer to write.
|
||||
*
|
||||
* @param length
|
||||
* The number of bytes in the buffer.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length);
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object state, writes the given string as a proper JSON string,
|
||||
* including starting and ending quotes. The contents of the string will be
|
||||
* escaped as necessary.
|
||||
*
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
* data must be flushed at all.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object containing the JSON buffer to which the given string
|
||||
* should be written as a JSON name/value pair.
|
||||
*
|
||||
* @param str
|
||||
* The string to write.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write_string(guac_user* user,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str);
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, writes the given JSON property name/value pair. The
|
||||
* name and value will be written as proper JSON strings separated by a colon.
|
||||
*
|
||||
* @param user
|
||||
* The user to which the data will be flushed as necessary.
|
||||
*
|
||||
* @param stream
|
||||
* The stream through which the flushed data should be sent as a blob, if
|
||||
* data must be flushed at all.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object containing the JSON buffer to which the given strings
|
||||
* should be written as a JSON name/value pair.
|
||||
*
|
||||
* @param name
|
||||
* The name of the property to write.
|
||||
*
|
||||
* @param value
|
||||
* The value of the property to write.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_write_property(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value);
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, initializes the state for writing a new JSON object. Note
|
||||
* that although the user and stream must be provided, no instruction or
|
||||
* blobs will be written due to any call to this function.
|
||||
*
|
||||
* @param user
|
||||
* The user associated with the given stream.
|
||||
*
|
||||
* @param stream
|
||||
* The stream associated with the JSON object being written.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object to initialize.
|
||||
*/
|
||||
void guac_common_json_begin_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
/**
|
||||
* Given a stream, the user to which it belongs, and the current stream state
|
||||
* of a JSON object, completes writing that JSON object by writing the final
|
||||
* terminating brace. This function must only be called following a
|
||||
* corresponding call to guac_common_json_begin_object().
|
||||
*
|
||||
* @param user
|
||||
* The user associated with the given stream.
|
||||
*
|
||||
* @param stream
|
||||
* The stream associated with the JSON object being written.
|
||||
*
|
||||
* @param json_state
|
||||
* The state object whose in-progress JSON object should be terminated.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if at least one blob was written, zero otherwise.
|
||||
*/
|
||||
int guac_common_json_end_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state);
|
||||
|
||||
#endif
|
||||
|
@ -1,23 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_LIST_H
|
61
src/common/common/pointer_cursor.h
Normal file
61
src/common/common/pointer_cursor.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUAC_COMMON_POINTER_CURSOR_H
|
||||
#define _GUAC_COMMON_POINTER_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_pointer_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_pointer_cursor[];
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param user The guac_user to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_pointer_cursor(guac_user* user);
|
||||
|
||||
#endif
|
143
src/common/common/rect.h
Normal file
143
src/common/common/rect.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_RECT_H
|
||||
#define __GUAC_COMMON_RECT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Simple representation of a rectangle, having a defined corner and dimensions.
|
||||
*/
|
||||
typedef struct guac_common_rect {
|
||||
|
||||
/**
|
||||
* The X coordinate of the upper-left corner of this rectangle.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the upper-left corner of this rectangle.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* The width of this rectangle.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of this rectangle.
|
||||
*/
|
||||
int height;
|
||||
|
||||
} guac_common_rect;
|
||||
|
||||
/**
|
||||
* Initialize the given rect with the given coordinates and dimensions.
|
||||
*
|
||||
* @param rect The rect to initialize.
|
||||
* @param x The X coordinate of the upper-left corner of the rect.
|
||||
* @param y The Y coordinate of the upper-left corner of the rect.
|
||||
* @param width The width of the rect.
|
||||
* @param height The height of the rect.
|
||||
*/
|
||||
void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* Expand the rectangle to fit an NxN grid.
|
||||
*
|
||||
* The rectangle will be shifted to the left and up, expanded and adjusted to
|
||||
* fit within the max bounding rect.
|
||||
*
|
||||
* @param cell_size
|
||||
* The (NxN) grid cell size.
|
||||
*
|
||||
* @param rect
|
||||
* The rectangle to adjust.
|
||||
*
|
||||
* @param max_rect
|
||||
* The bounding area in which the given rect can exist.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect,
|
||||
const guac_common_rect* max_rect);
|
||||
|
||||
/**
|
||||
* Extend the given rect such that it contains at least the specified minimum
|
||||
* rect.
|
||||
*
|
||||
* @param rect The rect to extend.
|
||||
* @param min The minimum area which must be contained within the given rect.
|
||||
*/
|
||||
void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min);
|
||||
|
||||
/**
|
||||
* Collapse the given rect such that it exists only within the given maximum
|
||||
* rect.
|
||||
*
|
||||
* @param rect The rect to extend.
|
||||
* @param max The maximum area in which the given rect can exist.
|
||||
*/
|
||||
void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max);
|
||||
|
||||
/**
|
||||
* Check whether a rectangle intersects another.
|
||||
*
|
||||
* @param rect
|
||||
* Rectangle to check for intersection.
|
||||
*
|
||||
* @param other
|
||||
* The other rectangle.
|
||||
*
|
||||
* @return
|
||||
* Zero if no intersection, 1 if partial intersection,
|
||||
* 2 if first rect is completely inside the other.
|
||||
*/
|
||||
int guac_common_rect_intersects(const guac_common_rect* rect,
|
||||
const guac_common_rect* other);
|
||||
|
||||
/**
|
||||
* Clip and split a rectangle into rectangles which are not covered by the
|
||||
* hole rectangle.
|
||||
*
|
||||
* This function will clip and split single edges when executed and must be
|
||||
* invoked until it returns zero. The edges are handled counter-clockwise
|
||||
* starting at the top edge.
|
||||
*
|
||||
* @param rect
|
||||
* The rectangle to be split. This rectangle will be clipped by the
|
||||
* split_rect.
|
||||
*
|
||||
* @param hole
|
||||
* The rectangle which represents the hole.
|
||||
*
|
||||
* @param split_rect
|
||||
* Resulting split rectangle.
|
||||
*
|
||||
* @return
|
||||
* Zero when no splits were done, non-zero when the rectangle was split.
|
||||
*/
|
||||
int guac_common_rect_clip_and_split(guac_common_rect* rect,
|
||||
const guac_common_rect* hole, guac_common_rect* split_rect);
|
||||
|
||||
#endif
|
||||
|
47
src/common/common/string.h
Normal file
47
src/common/common/string.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_STRING_H
|
||||
#define __GUAC_COMMON_STRING_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Counts the number of occurrences of a given character in a string.
|
||||
*
|
||||
* @param string The string to count occurrences within.
|
||||
* @param c The character to count occurrences of.
|
||||
* @return The number of occurrences.
|
||||
*/
|
||||
int guac_count_occurrences(const char* string, char c);
|
||||
|
||||
/**
|
||||
* Splits a string into a newly-allocated array of strings. The array itself
|
||||
* and each string within the array will eventually need to be freed. The array
|
||||
* is NULL-terminated.
|
||||
*
|
||||
* @param string The string to split.
|
||||
* @param delim The character which separates individual substrings within the
|
||||
* given string.
|
||||
* @return A newly-allocated, NULL-terminated array of strings.
|
||||
*/
|
||||
char** guac_split(const char* string, char delim);
|
||||
|
||||
#endif
|
||||
|
539
src/common/common/surface.h
Normal file
539
src/common/common/surface.h
Normal file
@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_SURFACE_H
|
||||
#define __GUAC_COMMON_SURFACE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "rect.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* The maximum number of updates to allow within the bitmap queue.
|
||||
*/
|
||||
#define GUAC_COMMON_SURFACE_QUEUE_SIZE 256
|
||||
|
||||
/**
|
||||
* Heat map cell size in pixels. Each side of each heat map cell will consist
|
||||
* of this many pixels.
|
||||
*/
|
||||
#define GUAC_COMMON_SURFACE_HEAT_CELL_SIZE 64
|
||||
|
||||
/**
|
||||
* The width or height of the heat map (in cells) given the width or height of
|
||||
* the image (in pixels).
|
||||
*/
|
||||
#define GUAC_COMMON_SURFACE_HEAT_DIMENSION(x) ( \
|
||||
(x + GUAC_COMMON_SURFACE_HEAT_CELL_SIZE - 1) \
|
||||
/ GUAC_COMMON_SURFACE_HEAT_CELL_SIZE \
|
||||
)
|
||||
|
||||
/**
|
||||
* The number of entries to collect within each heat map cell. Collected
|
||||
* history entries are used to determine the framerate of the region associated
|
||||
* with that cell.
|
||||
*/
|
||||
#define GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE 5
|
||||
|
||||
/**
|
||||
* Representation of a cell in the refresh heat map. This cell is used to keep
|
||||
* track of how often an area on a surface is refreshed.
|
||||
*/
|
||||
typedef struct guac_common_surface_heat_cell {
|
||||
|
||||
/**
|
||||
* Timestamps of each of the last N updates covering the location
|
||||
* associated with this heat map cell. This is used to calculate the
|
||||
* framerate. This array is structured as a ring buffer containing history
|
||||
* entries in chronologically-ascending order, starting at the entry
|
||||
* pointed to by oldest_entry and proceeding through all other entries,
|
||||
* wrapping around if the end of the array is reached.
|
||||
*/
|
||||
guac_timestamp history[GUAC_COMMON_SURFACE_HEAT_CELL_HISTORY_SIZE];
|
||||
|
||||
/**
|
||||
* Index of the oldest entry within the history.
|
||||
*/
|
||||
int oldest_entry;
|
||||
|
||||
} guac_common_surface_heat_cell;
|
||||
|
||||
/**
|
||||
* Representation of a bitmap update, having a rectangle of image data (stored
|
||||
* elsewhere) and a flushed/not-flushed state.
|
||||
*/
|
||||
typedef struct guac_common_surface_bitmap_rect {
|
||||
|
||||
/**
|
||||
* Whether this rectangle has been flushed.
|
||||
*/
|
||||
int flushed;
|
||||
|
||||
/**
|
||||
* The rectangle containing the bitmap update.
|
||||
*/
|
||||
guac_common_rect rect;
|
||||
|
||||
} guac_common_surface_bitmap_rect;
|
||||
|
||||
/**
|
||||
* Surface which backs a Guacamole buffer or layer, automatically
|
||||
* combining updates when possible.
|
||||
*/
|
||||
typedef struct guac_common_surface {
|
||||
|
||||
/**
|
||||
* The layer this surface will draw to.
|
||||
*/
|
||||
const guac_layer* layer;
|
||||
|
||||
/**
|
||||
* The client associated with this surface.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The socket to send instructions on when flushing.
|
||||
*/
|
||||
guac_socket* socket;
|
||||
|
||||
/**
|
||||
* The number of simultaneous touches that this surface can accept, where 0
|
||||
* indicates that the surface does not support touch events at all.
|
||||
*/
|
||||
int touches;
|
||||
|
||||
/**
|
||||
* Non-zero if all graphical updates for this surface should use lossless
|
||||
* compression, 0 otherwise. By default, newly-created surfaces will use
|
||||
* lossy compression when heuristics determine it is appropriate.
|
||||
*/
|
||||
int lossless;
|
||||
|
||||
/**
|
||||
* The X coordinate of the upper-left corner of this layer, in pixels,
|
||||
* relative to its parent layer. This is only applicable to visible
|
||||
* (non-buffer) layers which are not the default layer.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the upper-left corner of this layer, in pixels,
|
||||
* relative to its parent layer. This is only applicable to visible
|
||||
* (non-buffer) layers which are not the default layer.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* The Z-order of this layer, relative to sibling layers. This is only
|
||||
* applicable to visible (non-buffer) layers which are not the default
|
||||
* layer.
|
||||
*/
|
||||
int z;
|
||||
|
||||
/**
|
||||
* The level of opacity applied to this layer. Fully opaque is 255, while
|
||||
* fully transparent is 0. This is only applicable to visible (non-buffer)
|
||||
* layers which are not the default layer.
|
||||
*/
|
||||
int opacity;
|
||||
|
||||
/**
|
||||
* The layer which contains this layer. This is only applicable to visible
|
||||
* (non-buffer) layers which are not the default layer.
|
||||
*/
|
||||
const guac_layer* parent;
|
||||
|
||||
/**
|
||||
* The width of this layer, in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of this layer, in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The size of each image row, in bytes.
|
||||
*/
|
||||
int stride;
|
||||
|
||||
/**
|
||||
* The underlying buffer of the Cairo surface.
|
||||
*/
|
||||
unsigned char* buffer;
|
||||
|
||||
/**
|
||||
* Non-zero if the location or parent layer of this surface has been
|
||||
* changed and needs to be flushed, 0 otherwise.
|
||||
*/
|
||||
int location_dirty;
|
||||
|
||||
/**
|
||||
* Non-zero if the opacity of this surface has been changed and needs to be
|
||||
* flushed, 0 otherwise.
|
||||
*/
|
||||
int opacity_dirty;
|
||||
|
||||
/**
|
||||
* Non-zero if this surface is dirty and needs to be flushed, 0 otherwise.
|
||||
*/
|
||||
int dirty;
|
||||
|
||||
/**
|
||||
* The dirty rectangle.
|
||||
*/
|
||||
guac_common_rect dirty_rect;
|
||||
|
||||
/**
|
||||
* Whether the surface actually exists on the client.
|
||||
*/
|
||||
int realized;
|
||||
|
||||
/**
|
||||
* Whether drawing operations are currently clipped by the clipping
|
||||
* rectangle.
|
||||
*/
|
||||
int clipped;
|
||||
|
||||
/**
|
||||
* The clipping rectangle.
|
||||
*/
|
||||
guac_common_rect clip_rect;
|
||||
|
||||
/**
|
||||
* The number of updates in the bitmap queue.
|
||||
*/
|
||||
int bitmap_queue_length;
|
||||
|
||||
/**
|
||||
* All queued bitmap updates.
|
||||
*/
|
||||
guac_common_surface_bitmap_rect bitmap_queue[GUAC_COMMON_SURFACE_QUEUE_SIZE];
|
||||
|
||||
/**
|
||||
* A heat map keeping track of the refresh frequency of
|
||||
* the areas of the screen.
|
||||
*/
|
||||
guac_common_surface_heat_cell* heat_map;
|
||||
|
||||
/**
|
||||
* Mutex which is locked internally when access to the surface must be
|
||||
* synchronized. All public functions of guac_common_surface should be
|
||||
* considered threadsafe.
|
||||
*/
|
||||
pthread_mutex_t _lock;
|
||||
|
||||
} guac_common_surface;
|
||||
|
||||
/**
|
||||
* Allocates a new guac_common_surface, assigning it to the given layer.
|
||||
*
|
||||
* @param client
|
||||
* The client associated with the given layer.
|
||||
*
|
||||
* @param socket
|
||||
* The socket to send instructions on when flushing.
|
||||
*
|
||||
* @param layer
|
||||
* The layer to associate with the new surface.
|
||||
*
|
||||
* @param w
|
||||
* The width of the surface.
|
||||
*
|
||||
* @param h
|
||||
* The height of the surface.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated guac_common_surface.
|
||||
*/
|
||||
guac_common_surface* guac_common_surface_alloc(guac_client* client,
|
||||
guac_socket* socket, const guac_layer* layer, int w, int h);
|
||||
|
||||
/**
|
||||
* Frees the given guac_common_surface. Beware that this will NOT free any
|
||||
* associated layers, which must be freed manually.
|
||||
*
|
||||
* @param surface The surface to free.
|
||||
*/
|
||||
void guac_common_surface_free(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Resizes the given surface to the given size.
|
||||
*
|
||||
* @param surface The surface to resize.
|
||||
* @param w The width of the surface.
|
||||
* @param h The height of the surface.
|
||||
*/
|
||||
void guac_common_surface_resize(guac_common_surface* surface, int w, int h);
|
||||
|
||||
/**
|
||||
* Draws the given data to the given guac_common_surface. If the source surface
|
||||
* is ARGB, the draw operation will be performed using the Porter-Duff "over"
|
||||
* composite operator. If the source surface is RGB (no alpha channel), no
|
||||
* compositing is performed and destination pixels are ignored.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to draw to.
|
||||
*
|
||||
* @param x
|
||||
* The X coordinate of the draw location.
|
||||
*
|
||||
* @param y
|
||||
* The Y coordinate of the draw location.
|
||||
*
|
||||
* @param src
|
||||
* The Cairo surface to retrieve data from.
|
||||
*/
|
||||
void guac_common_surface_draw(guac_common_surface* surface, int x, int y,
|
||||
cairo_surface_t* src);
|
||||
|
||||
/**
|
||||
* Paints to the given guac_common_surface using the given data as a stencil,
|
||||
* filling opaque regions with the specified color, and leaving transparent
|
||||
* regions untouched.
|
||||
*
|
||||
* @param surface The surface to draw to.
|
||||
* @param x The X coordinate of the draw location.
|
||||
* @param y The Y coordinate of the draw location.
|
||||
* @param src The Cairo surface to retrieve data from.
|
||||
* @param red The red component of the fill color.
|
||||
* @param green The green component of the fill color.
|
||||
* @param blue The blue component of the fill color.
|
||||
*/
|
||||
void guac_common_surface_paint(guac_common_surface* surface, int x, int y, cairo_surface_t* src,
|
||||
int red, int green, int blue);
|
||||
|
||||
/**
|
||||
* Copies a rectangle of data between two surfaces.
|
||||
*
|
||||
* @param src The source surface.
|
||||
* @param sx The X coordinate of the upper-left corner of the source rect.
|
||||
* @param sy The Y coordinate of the upper-left corner of the source rect.
|
||||
* @param w The width of the source rect.
|
||||
* @param h The height of the source rect.
|
||||
* @param dst The destination surface.
|
||||
* @param dx The X coordinate of the upper-left corner of the destination rect.
|
||||
* @param dy The Y coordinate of the upper-left corner of the destination rect.
|
||||
*/
|
||||
void guac_common_surface_copy(guac_common_surface* src, int sx, int sy, int w, int h,
|
||||
guac_common_surface* dst, int dx, int dy);
|
||||
|
||||
/**
|
||||
* Transfers a rectangle of data between two surfaces.
|
||||
*
|
||||
* @param src The source surface.
|
||||
* @param sx The X coordinate of the upper-left corner of the source rect.
|
||||
* @param sy The Y coordinate of the upper-left corner of the source rect.
|
||||
* @param w The width of the source rect.
|
||||
* @param h The height of the source rect.
|
||||
* @param op The transfer function.
|
||||
* @param dst The destination surface.
|
||||
* @param dx The X coordinate of the upper-left corner of the destination rect.
|
||||
* @param dy The Y coordinate of the upper-left corner of the destination rect.
|
||||
*/
|
||||
void guac_common_surface_transfer(guac_common_surface* src, int sx, int sy, int w, int h,
|
||||
guac_transfer_function op, guac_common_surface* dst, int dx, int dy);
|
||||
|
||||
/**
|
||||
* Assigns the given value to all pixels within a rectangle of the given
|
||||
* surface. The color of all pixels within the rectangle, including the alpha
|
||||
* component, is entirely replaced.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to draw upon.
|
||||
*
|
||||
* @param x
|
||||
* The X coordinate of the upper-left corner of the rectangle.
|
||||
*
|
||||
* @param y
|
||||
* The Y coordinate of the upper-left corner of the rectangle.
|
||||
*
|
||||
* @param w
|
||||
* The width of the rectangle.
|
||||
*
|
||||
* @param h
|
||||
* The height of the rectangle.
|
||||
*
|
||||
* @param red
|
||||
* The red component of the color value to assign to all pixels within the
|
||||
* rectangle.
|
||||
*
|
||||
* @param green
|
||||
* The green component of the color value to assign to all pixels within
|
||||
* the rectangle.
|
||||
*
|
||||
* @param blue
|
||||
* The blue component of the color value to assign to all pixels within the
|
||||
* rectangle.
|
||||
*
|
||||
* @param alpha
|
||||
* The alpha component of the color value to assign to all pixels within
|
||||
* the rectangle.
|
||||
*/
|
||||
void guac_common_surface_set(guac_common_surface* surface, int x, int y,
|
||||
int w, int h, int red, int green, int blue, int alpha);
|
||||
|
||||
/**
|
||||
* Given the coordinates and dimensions of a rectangle, clips all future
|
||||
* operations within that rectangle.
|
||||
*
|
||||
* @param surface The surface whose clipping rectangle should be changed.
|
||||
* @param x The X coordinate of the upper-left corner of the bounding rectangle.
|
||||
* @param y The Y coordinate of the upper-left corner of the bounding rectangle.
|
||||
* @param w The width of the bounding rectangle.
|
||||
* @param h The height of the bounding rectangle.
|
||||
*/
|
||||
void guac_common_surface_clip(guac_common_surface* surface, int x, int y, int w, int h);
|
||||
|
||||
/**
|
||||
* Resets the clipping rectangle, allowing drawing operations throughout the
|
||||
* entire surface.
|
||||
*
|
||||
* @param surface The surface whose clipping rectangle should be reset.
|
||||
*/
|
||||
void guac_common_surface_reset_clip(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Changes the location of the surface relative to its parent layer. If the
|
||||
* surface does not represent a non-default visible layer, then this function
|
||||
* has no effect.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to move relative to its parent layer.
|
||||
*
|
||||
* @param x
|
||||
* The new X coordinate for the upper-left corner of the layer, in pixels.
|
||||
*
|
||||
* @param y
|
||||
* The new Y coordinate for the upper-left corner of the layer, in pixels.
|
||||
*/
|
||||
void guac_common_surface_move(guac_common_surface* surface, int x, int y);
|
||||
|
||||
/**
|
||||
* Changes the stacking order of the surface relative to other surfaces within
|
||||
* the same parent layer. If the surface does not represent a non-default
|
||||
* visible layer, then this function has no effect.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to reorder relative to sibling layers.
|
||||
*
|
||||
* @param z
|
||||
* The new Z-order for this layer, relative to sibling layers.
|
||||
*/
|
||||
void guac_common_surface_stack(guac_common_surface* surface, int z);
|
||||
|
||||
/**
|
||||
* Changes the parent layer of ths given surface. By default, layers will be
|
||||
* children of the default layer. If the surface does not represent a
|
||||
* non-default visible layer, then this function has no effect.
|
||||
*
|
||||
* @param surface
|
||||
* The surface whose parent layer should be changed.
|
||||
*
|
||||
* @param parent
|
||||
* The layer which should be set as the new parent of the given surface.
|
||||
*/
|
||||
void guac_common_surface_set_parent(guac_common_surface* surface,
|
||||
const guac_layer* parent);
|
||||
|
||||
/**
|
||||
* Sets the opacity of the surface. If the surface does not represent a
|
||||
* non-default visible layer, then this function has no effect.
|
||||
*
|
||||
* @param surface
|
||||
* The surface whose opacity should be changed.
|
||||
*
|
||||
* @param opacity
|
||||
* The level of opacity applied to this surface, where fully opaque is 255,
|
||||
* and fully transparent is 0.
|
||||
*/
|
||||
void guac_common_surface_set_opacity(guac_common_surface* surface, int opacity);
|
||||
|
||||
/**
|
||||
* Flushes the given surface, including any applicable properties, drawing any
|
||||
* pending operations on the remote display.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to flush.
|
||||
*/
|
||||
void guac_common_surface_flush(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Duplicates the contents of the current surface to the given socket. Pending
|
||||
* changes are not flushed.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to duplicate.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the surface.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which the surface contents should be sent.
|
||||
*/
|
||||
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
||||
guac_socket* socket);
|
||||
|
||||
/**
|
||||
* Declares that the given surface should receive touch events. By default,
|
||||
* surfaces are assumed to not expect touch events. This value is advisory, and
|
||||
* the client is not required to honor the declared level of touch support.
|
||||
* Implementations are expected to safely handle or ignore any received touch
|
||||
* events, regardless of the level of touch support declared. regardless of
|
||||
* the level of touch support declared.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to modify.
|
||||
*
|
||||
* @param touches
|
||||
* The number of simultaneous touches that this surface can accept, where 0
|
||||
* indicates that the surface does not support touch events at all.
|
||||
*/
|
||||
void guac_common_surface_set_multitouch(guac_common_surface* surface,
|
||||
int touches);
|
||||
|
||||
/**
|
||||
* Sets the lossless compression policy of the given surface to the given
|
||||
* value. By default, newly-created surfaces will use lossy compression for
|
||||
* graphical updates when heuristics determine that doing so is appropriate.
|
||||
* Specifying a non-zero value here will force all graphical updates to always
|
||||
* use lossless compression, whereas specifying zero will restore the default
|
||||
* policy.
|
||||
*
|
||||
* @param surface
|
||||
* The surface to modify.
|
||||
*
|
||||
* @param lossless
|
||||
* Non-zero if all graphical updates for this surface should use lossless
|
||||
* compression, 0 otherwise.
|
||||
*/
|
||||
void guac_common_surface_set_lossless(guac_common_surface* surface,
|
||||
int lossless);
|
||||
|
||||
#endif
|
||||
|
306
src/common/cursor.c
Normal file
306
src/common/cursor.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/blank_cursor.h"
|
||||
#include "common/dot_cursor.h"
|
||||
#include "common/cursor.h"
|
||||
#include "common/ibar_cursor.h"
|
||||
#include "common/pointer_cursor.h"
|
||||
#include "common/surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* Allocates a cursor as well as an image buffer where the cursor is rendered.
|
||||
*
|
||||
* @param client
|
||||
* The client owning the cursor.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated cursor or NULL if cursor cannot be allocated.
|
||||
*/
|
||||
guac_common_cursor* guac_common_cursor_alloc(guac_client* client) {
|
||||
|
||||
guac_common_cursor* cursor = malloc(sizeof(guac_common_cursor));
|
||||
if (cursor == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Associate cursor with client and allocate cursor buffer */
|
||||
cursor->client = client;
|
||||
cursor->buffer = guac_client_alloc_buffer(client);
|
||||
|
||||
/* Allocate initial image buffer */
|
||||
cursor->image_buffer_size = GUAC_COMMON_CURSOR_DEFAULT_SIZE;
|
||||
cursor->image_buffer = malloc(cursor->image_buffer_size);
|
||||
|
||||
/* No cursor image yet */
|
||||
cursor->width = 0;
|
||||
cursor->height = 0;
|
||||
cursor->surface = NULL;
|
||||
cursor->hotspot_x = 0;
|
||||
cursor->hotspot_y = 0;
|
||||
|
||||
/* No user has moved the mouse yet */
|
||||
cursor->user = NULL;
|
||||
cursor->timestamp = guac_timestamp_current();
|
||||
|
||||
/* Start cursor in upper-left */
|
||||
cursor->x = 0;
|
||||
cursor->y = 0;
|
||||
|
||||
return cursor;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_free(guac_common_cursor* cursor) {
|
||||
|
||||
guac_client* client = cursor->client;
|
||||
guac_layer* buffer = cursor->buffer;
|
||||
cairo_surface_t* surface = cursor->surface;
|
||||
|
||||
/* Free image buffer and surface */
|
||||
free(cursor->image_buffer);
|
||||
if (surface != NULL)
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
/* Destroy buffer within remotely-connected client */
|
||||
guac_protocol_send_dispose(client->socket, buffer);
|
||||
|
||||
/* Return buffer to pool */
|
||||
guac_client_free_buffer(client, buffer);
|
||||
|
||||
free(cursor);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
/* Synchronize location */
|
||||
guac_protocol_send_mouse(socket, cursor->x, cursor->y, cursor->button_mask,
|
||||
cursor->timestamp);
|
||||
|
||||
/* Synchronize cursor image */
|
||||
if (cursor->surface != NULL) {
|
||||
guac_protocol_send_size(socket, cursor->buffer,
|
||||
cursor->width, cursor->height);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC,
|
||||
cursor->buffer, 0, 0, cursor->surface);
|
||||
|
||||
guac_protocol_send_cursor(socket,
|
||||
cursor->hotspot_x, cursor->hotspot_y,
|
||||
cursor->buffer, 0, 0, cursor->width, cursor->height);
|
||||
}
|
||||
|
||||
guac_socket_flush(socket);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for guac_client_foreach_user() which sends the current cursor
|
||||
* position and button state to any given user except the user that moved the
|
||||
* cursor last.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to the guac_common_cursor whose state should be broadcast to
|
||||
* all users except the user that moved the cursor last.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
static void* guac_common_cursor_broadcast_state(guac_user* user,
|
||||
void* data) {
|
||||
|
||||
guac_common_cursor* cursor = (guac_common_cursor*) data;
|
||||
|
||||
/* Send cursor state only if the user is not moving the cursor */
|
||||
if (user != cursor->user) {
|
||||
guac_protocol_send_mouse(user->socket, cursor->x, cursor->y,
|
||||
cursor->button_mask, cursor->timestamp);
|
||||
guac_socket_flush(user->socket);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user,
|
||||
int x, int y, int button_mask) {
|
||||
|
||||
/* Update current user of cursor */
|
||||
cursor->user = user;
|
||||
|
||||
/* Update cursor state */
|
||||
cursor->x = x;
|
||||
cursor->y = y;
|
||||
cursor->button_mask = button_mask;
|
||||
|
||||
/* Store time at which cursor was updated */
|
||||
cursor->timestamp = guac_timestamp_current();
|
||||
|
||||
/* Notify all other users of change in cursor state */
|
||||
guac_client_foreach_user(cursor->client,
|
||||
guac_common_cursor_broadcast_state, cursor);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the cursor image buffer has enough room to fit an image with the
|
||||
* given characteristics. Existing image buffer data may be destroyed.
|
||||
*
|
||||
* @param cursor
|
||||
* The cursor whose buffer size should be checked. If this cursor lacks
|
||||
* sufficient space to contain a cursor image of the specified width,
|
||||
* height, and stride, the current contents of this cursor will be
|
||||
* destroyed and replaced with an new buffer having sufficient space.
|
||||
*
|
||||
* @param width
|
||||
* The required cursor width, in pixels.
|
||||
*
|
||||
* @param height
|
||||
* The required cursor height, in pixels.
|
||||
*
|
||||
* @param stride
|
||||
* The number of bytes in each row of image data.
|
||||
*/
|
||||
static void guac_common_cursor_resize(guac_common_cursor* cursor,
|
||||
int width, int height, int stride) {
|
||||
|
||||
int minimum_size = height * stride;
|
||||
|
||||
/* Grow image buffer if necessary */
|
||||
if (cursor->image_buffer_size < minimum_size) {
|
||||
|
||||
/* Calculate new size */
|
||||
cursor->image_buffer_size = minimum_size*2;
|
||||
|
||||
/* Destructively reallocate image buffer */
|
||||
free(cursor->image_buffer);
|
||||
cursor->image_buffer = malloc(cursor->image_buffer_size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy,
|
||||
unsigned const char* data, int width, int height, int stride) {
|
||||
|
||||
/* Copy image data */
|
||||
guac_common_cursor_resize(cursor, width, height, stride);
|
||||
memcpy(cursor->image_buffer, data, height * stride);
|
||||
|
||||
if (cursor->surface != NULL)
|
||||
cairo_surface_destroy(cursor->surface);
|
||||
|
||||
cursor->surface = cairo_image_surface_create_for_data(cursor->image_buffer,
|
||||
CAIRO_FORMAT_ARGB32, width, height, stride);
|
||||
|
||||
/* Set new cursor parameters */
|
||||
cursor->width = width;
|
||||
cursor->height = height;
|
||||
cursor->hotspot_x = hx;
|
||||
cursor->hotspot_y = hy;
|
||||
|
||||
/* Broadcast new cursor image to all users */
|
||||
guac_protocol_send_size(cursor->client->socket, cursor->buffer,
|
||||
width, height);
|
||||
|
||||
guac_client_stream_png(cursor->client, cursor->client->socket,
|
||||
GUAC_COMP_SRC, cursor->buffer, 0, 0, cursor->surface);
|
||||
|
||||
/* Update cursor image */
|
||||
guac_protocol_send_cursor(cursor->client->socket,
|
||||
cursor->hotspot_x, cursor->hotspot_y,
|
||||
cursor->buffer, 0, 0, cursor->width, cursor->height);
|
||||
|
||||
guac_socket_flush(cursor->client->socket);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy,
|
||||
guac_common_surface* surface) {
|
||||
|
||||
/* Set cursor to surface contents */
|
||||
guac_common_cursor_set_argb(cursor, hx, hy, surface->buffer,
|
||||
surface->width, surface->height, surface->stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_pointer(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 0, 0,
|
||||
guac_common_pointer_cursor,
|
||||
guac_common_pointer_cursor_width,
|
||||
guac_common_pointer_cursor_height,
|
||||
guac_common_pointer_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_dot(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 2, 2,
|
||||
guac_common_dot_cursor,
|
||||
guac_common_dot_cursor_width,
|
||||
guac_common_dot_cursor_height,
|
||||
guac_common_dot_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_ibar(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor,
|
||||
guac_common_ibar_cursor_width / 2,
|
||||
guac_common_ibar_cursor_height / 2,
|
||||
guac_common_ibar_cursor,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height,
|
||||
guac_common_ibar_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_set_blank(guac_common_cursor* cursor) {
|
||||
|
||||
guac_common_cursor_set_argb(cursor, 0, 0,
|
||||
guac_common_blank_cursor,
|
||||
guac_common_blank_cursor_width,
|
||||
guac_common_blank_cursor_height,
|
||||
guac_common_blank_cursor_stride);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_cursor_remove_user(guac_common_cursor* cursor,
|
||||
guac_user* user) {
|
||||
|
||||
/* Disassociate from given user */
|
||||
if (cursor->user == user)
|
||||
cursor->user = NULL;
|
||||
|
||||
}
|
||||
|
391
src/common/display.c
Normal file
391
src/common/display.c
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/cursor.h"
|
||||
#include "common/display.h"
|
||||
#include "common/surface.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Synchronizes all surfaces within the given linked list to the given socket.
|
||||
* If the provided pointer to the linked list is NULL, this function has no
|
||||
* effect.
|
||||
*
|
||||
* @param layers
|
||||
* The head element of the linked list of layers to synchronize, which may
|
||||
* be NULL if the list is currently empty.
|
||||
*
|
||||
* @param user
|
||||
* The user receiving the layers.
|
||||
*
|
||||
* @param socket
|
||||
* The socket over which each layer should be sent.
|
||||
*/
|
||||
static void guac_common_display_dup_layers(guac_common_display_layer* layers,
|
||||
guac_user* user, guac_socket* socket) {
|
||||
|
||||
guac_common_display_layer* current = layers;
|
||||
|
||||
/* Synchronize all surfaces in given list */
|
||||
while (current != NULL) {
|
||||
guac_common_surface_dup(current->surface, user, socket);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all layers and associated surfaces within the given list, as well as
|
||||
* their corresponding list elements. If the provided pointer to the linked
|
||||
* list is NULL, this function has no effect.
|
||||
*
|
||||
* @param layers
|
||||
* The head element of the linked list of layers to free, which may be NULL
|
||||
* if the list is currently empty.
|
||||
*
|
||||
* @param client
|
||||
* The client owning the layers wrapped by each of the layers in the list.
|
||||
*/
|
||||
static void guac_common_display_free_layers(guac_common_display_layer* layers,
|
||||
guac_client* client) {
|
||||
|
||||
guac_common_display_layer* current = layers;
|
||||
|
||||
/* Free each surface in given list */
|
||||
while (current != NULL) {
|
||||
|
||||
guac_common_display_layer* next = current->next;
|
||||
guac_layer* layer = current->layer;
|
||||
|
||||
/* Free surface */
|
||||
guac_common_surface_free(current->surface);
|
||||
|
||||
/* Destroy layer within remotely-connected client */
|
||||
guac_protocol_send_dispose(client->socket, layer);
|
||||
|
||||
/* Free layer or buffer depending on index */
|
||||
if (layer->index < 0)
|
||||
guac_client_free_buffer(client, layer);
|
||||
else if (layer->index > 0)
|
||||
guac_client_free_layer(client, layer);
|
||||
|
||||
/* Free current element and advance to next */
|
||||
free(current);
|
||||
current = next;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a display and a cursor which are used to represent the remote
|
||||
* display and cursor.
|
||||
*
|
||||
* @param client
|
||||
* The client owning the cursor.
|
||||
*
|
||||
* @param width
|
||||
* The desired width of the display.
|
||||
*
|
||||
* @param height
|
||||
* The desired height of the display.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated display or NULL if display cannot be allocated.
|
||||
*/
|
||||
guac_common_display* guac_common_display_alloc(guac_client* client,
|
||||
int width, int height) {
|
||||
|
||||
/* Allocate display */
|
||||
guac_common_display* display = malloc(sizeof(guac_common_display));
|
||||
if (display == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Allocate shared cursor */
|
||||
display->cursor = guac_common_cursor_alloc(client);
|
||||
if (display->cursor == NULL) {
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&display->_lock, NULL);
|
||||
|
||||
/* Associate display with given client */
|
||||
display->client = client;
|
||||
|
||||
display->default_surface = guac_common_surface_alloc(client,
|
||||
client->socket, GUAC_DEFAULT_LAYER, width, height);
|
||||
|
||||
/* No initial layers or buffers */
|
||||
display->layers = NULL;
|
||||
display->buffers = NULL;
|
||||
|
||||
return display;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free(guac_common_display* display) {
|
||||
|
||||
/* Free shared cursor */
|
||||
guac_common_cursor_free(display->cursor);
|
||||
|
||||
/* Free default surface */
|
||||
guac_common_surface_free(display->default_surface);
|
||||
|
||||
/* Free all layers and buffers */
|
||||
guac_common_display_free_layers(display->buffers, display->client);
|
||||
guac_common_display_free_layers(display->layers, display->client);
|
||||
|
||||
pthread_mutex_destroy(&display->_lock);
|
||||
free(display);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_dup(guac_common_display* display, guac_user* user,
|
||||
guac_socket* socket) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Sunchronize shared cursor */
|
||||
guac_common_cursor_dup(display->cursor, user, socket);
|
||||
|
||||
/* Synchronize default surface */
|
||||
guac_common_surface_dup(display->default_surface, user, socket);
|
||||
|
||||
/* Synchronize all layers and buffers */
|
||||
guac_common_display_dup_layers(display->layers, user, socket);
|
||||
guac_common_display_dup_layers(display->buffers, user, socket);
|
||||
|
||||
/* Sends a sync instruction to mark the boundary of the first frame */
|
||||
guac_protocol_send_sync(socket, client->last_sent_timestamp, 1);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_set_lossless(guac_common_display* display,
|
||||
int lossless) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Update lossless setting to be applied to all newly-allocated
|
||||
* layers/buffers */
|
||||
display->lossless = lossless;
|
||||
|
||||
/* Update losslessness of all allocated layers/buffers */
|
||||
guac_common_display_layer* current = display->layers;
|
||||
while (current != NULL) {
|
||||
guac_common_surface_set_lossless(current->surface, lossless);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
/* Update losslessness of default display layer (not included within layers
|
||||
* list) */
|
||||
guac_common_surface_set_lossless(display->default_surface, lossless);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_flush(guac_common_display* display) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
guac_common_display_layer* current = display->layers;
|
||||
|
||||
/* Flush all surfaces */
|
||||
while (current != NULL) {
|
||||
guac_common_surface_flush(current->surface);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
guac_common_surface_flush(display->default_surface);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates and inserts a new element into the given linked list of display
|
||||
* layers, associating it with the given layer and surface.
|
||||
*
|
||||
* @param head
|
||||
* A pointer to the head pointer of the list of layers. The head pointer
|
||||
* will be updated by this function to point to the newly-allocated
|
||||
* display layer.
|
||||
*
|
||||
* @param layer
|
||||
* The Guacamole layer to associated with the new display layer.
|
||||
*
|
||||
* @param surface
|
||||
* The surface associated with the given Guacamole layer and which should
|
||||
* be associated with the new display layer.
|
||||
*
|
||||
* @return
|
||||
* The newly-allocated display layer, which has been associated with the
|
||||
* provided layer and surface.
|
||||
*/
|
||||
static guac_common_display_layer* guac_common_display_add_layer(
|
||||
guac_common_display_layer** head, guac_layer* layer,
|
||||
guac_common_surface* surface) {
|
||||
|
||||
guac_common_display_layer* old_head = *head;
|
||||
|
||||
guac_common_display_layer* display_layer =
|
||||
malloc(sizeof(guac_common_display_layer));
|
||||
|
||||
/* Init layer/surface pair */
|
||||
display_layer->layer = layer;
|
||||
display_layer->surface = surface;
|
||||
|
||||
/* Insert list element as the new head */
|
||||
display_layer->prev = NULL;
|
||||
display_layer->next = old_head;
|
||||
*head = display_layer;
|
||||
|
||||
/* Update old head to point to new element, if it existed */
|
||||
if (old_head != NULL)
|
||||
old_head->prev = display_layer;
|
||||
|
||||
return display_layer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given display layer from the linked list whose head pointer is
|
||||
* provided.
|
||||
*
|
||||
* @param head
|
||||
* A pointer to the head pointer of the list of layers. The head pointer
|
||||
* will be updated by this function if necessary, and will be set to NULL
|
||||
* if the display layer being removed is the only layer in the list.
|
||||
*
|
||||
* @param display_layer
|
||||
* The display layer to remove from the given list.
|
||||
*/
|
||||
static void guac_common_display_remove_layer(guac_common_display_layer** head,
|
||||
guac_common_display_layer* display_layer) {
|
||||
|
||||
/* Update previous element, if it exists */
|
||||
if (display_layer->prev != NULL)
|
||||
display_layer->prev->next = display_layer->next;
|
||||
|
||||
/* If there is no previous element, update the list head */
|
||||
else
|
||||
*head = display_layer->next;
|
||||
|
||||
/* Update next element, if it exists */
|
||||
if (display_layer->next != NULL)
|
||||
display_layer->next->prev = display_layer->prev;
|
||||
|
||||
}
|
||||
|
||||
guac_common_display_layer* guac_common_display_alloc_layer(
|
||||
guac_common_display* display, int width, int height) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Allocate Guacamole layer */
|
||||
guac_layer* layer = guac_client_alloc_layer(display->client);
|
||||
|
||||
/* Allocate corresponding surface */
|
||||
guac_common_surface* surface = guac_common_surface_alloc(display->client,
|
||||
display->client->socket, layer, width, height);
|
||||
|
||||
/* Apply current display losslessness */
|
||||
guac_common_surface_set_lossless(surface, display->lossless);
|
||||
|
||||
/* Add layer and surface to list */
|
||||
guac_common_display_layer* display_layer =
|
||||
guac_common_display_add_layer(&display->layers, layer, surface);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
return display_layer;
|
||||
|
||||
}
|
||||
|
||||
guac_common_display_layer* guac_common_display_alloc_buffer(
|
||||
guac_common_display* display, int width, int height) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Allocate Guacamole buffer */
|
||||
guac_layer* buffer = guac_client_alloc_buffer(display->client);
|
||||
|
||||
/* Allocate corresponding surface */
|
||||
guac_common_surface* surface = guac_common_surface_alloc(display->client,
|
||||
display->client->socket, buffer, width, height);
|
||||
|
||||
/* Apply current display losslessness */
|
||||
guac_common_surface_set_lossless(surface, display->lossless);
|
||||
|
||||
/* Add buffer and surface to list */
|
||||
guac_common_display_layer* display_layer =
|
||||
guac_common_display_add_layer(&display->buffers, buffer, surface);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
return display_layer;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free_layer(guac_common_display* display,
|
||||
guac_common_display_layer* display_layer) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Remove list element from list */
|
||||
guac_common_display_remove_layer(&display->layers, display_layer);
|
||||
|
||||
/* Free associated layer and surface */
|
||||
guac_common_surface_free(display_layer->surface);
|
||||
guac_client_free_layer(display->client, display_layer->layer);
|
||||
|
||||
/* Free list element */
|
||||
free(display_layer);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_display_free_buffer(guac_common_display* display,
|
||||
guac_common_display_layer* display_buffer) {
|
||||
|
||||
pthread_mutex_lock(&display->_lock);
|
||||
|
||||
/* Remove list element from list */
|
||||
guac_common_display_remove_layer(&display->buffers, display_buffer);
|
||||
|
||||
/* Free associated layer and surface */
|
||||
guac_common_surface_free(display_buffer->surface);
|
||||
guac_client_free_buffer(display->client, display_buffer->layer);
|
||||
|
||||
/* Free list element */
|
||||
free(display_buffer);
|
||||
|
||||
pthread_mutex_unlock(&display->_lock);
|
||||
|
||||
}
|
@ -1,23 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -27,6 +24,7 @@
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
@ -52,9 +50,10 @@ unsigned char guac_common_dot_cursor[] = {
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_dot_cursor(guac_client* client) {
|
||||
void guac_common_set_dot_cursor(guac_user* user) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
@ -66,7 +65,8 @@ void guac_common_set_dot_cursor(guac_client* client) {
|
||||
guac_common_dot_cursor_height,
|
||||
guac_common_dot_cursor_stride);
|
||||
|
||||
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor, 0, 0, graphic);
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
@ -78,5 +78,8 @@ void guac_common_set_dot_cursor(guac_client* client) {
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic built-in dot.");
|
||||
|
||||
}
|
||||
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_clipboard.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
guac_common_clipboard* guac_common_clipboard_alloc(int size) {
|
||||
|
||||
guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard));
|
||||
|
||||
/* Init clipboard */
|
||||
clipboard->mimetype[0] = '\0';
|
||||
clipboard->buffer = malloc(size);
|
||||
clipboard->length = 0;
|
||||
clipboard->available = size;
|
||||
|
||||
return clipboard;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_free(guac_common_clipboard* clipboard) {
|
||||
free(clipboard->buffer);
|
||||
free(clipboard);
|
||||
}
|
||||
|
||||
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
|
||||
|
||||
char* current = clipboard->buffer;
|
||||
int remaining = clipboard->length;
|
||||
|
||||
/* Begin stream */
|
||||
guac_stream* stream = guac_client_alloc_stream(client);
|
||||
guac_protocol_send_clipboard(client->socket, stream, clipboard->mimetype);
|
||||
|
||||
/* Split clipboard into chunks */
|
||||
while (remaining > 0) {
|
||||
|
||||
/* Calculate size of next block */
|
||||
int block_size = GUAC_COMMON_CLIPBOARD_BLOCK_SIZE;
|
||||
if (remaining < block_size)
|
||||
block_size = remaining;
|
||||
|
||||
/* Send block */
|
||||
guac_protocol_send_blob(client->socket, stream, current, block_size);
|
||||
|
||||
/* Next block */
|
||||
remaining -= block_size;
|
||||
current += block_size;
|
||||
|
||||
}
|
||||
|
||||
/* End stream */
|
||||
guac_protocol_send_end(client->socket, stream);
|
||||
guac_client_free_stream(client, stream);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* mimetype) {
|
||||
clipboard->length = 0;
|
||||
strncpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype)-1);
|
||||
}
|
||||
|
||||
void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length) {
|
||||
|
||||
/* Truncate data to available length */
|
||||
int remaining = clipboard->available - clipboard->length;
|
||||
if (remaining < length)
|
||||
length = remaining;
|
||||
|
||||
/* Append to buffer */
|
||||
memcpy(clipboard->buffer + clipboard->length, data, length);
|
||||
|
||||
/* Update length */
|
||||
clipboard->length += length;
|
||||
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUAC_COMMON_DOT_CURSOR_H
|
||||
#define _GUAC_COMMON_DOT_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_dot_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_dot_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_dot_cursor[];
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_dot_cursor(guac_client* client);
|
||||
|
||||
#endif
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_iconv.h"
|
||||
|
||||
#include <guacamole/unicode.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Lookup table for Unicode code points, indexed by CP-1252 codepoint.
|
||||
*/
|
||||
const static int __GUAC_RDP_CP1252_CODEPOINT[32] = {
|
||||
0x20AC, /* 0x80 */
|
||||
0xFFFD, /* 0x81 */
|
||||
0x201A, /* 0x82 */
|
||||
0x0192, /* 0x83 */
|
||||
0x201E, /* 0x84 */
|
||||
0x2026, /* 0x85 */
|
||||
0x2020, /* 0x86 */
|
||||
0x2021, /* 0x87 */
|
||||
0x02C6, /* 0x88 */
|
||||
0x2030, /* 0x89 */
|
||||
0x0160, /* 0x8A */
|
||||
0x2039, /* 0x8B */
|
||||
0x0152, /* 0x8C */
|
||||
0xFFFD, /* 0x8D */
|
||||
0x017D, /* 0x8E */
|
||||
0xFFFD, /* 0x8F */
|
||||
0xFFFD, /* 0x90 */
|
||||
0x2018, /* 0x91 */
|
||||
0x2019, /* 0x92 */
|
||||
0x201C, /* 0x93 */
|
||||
0x201D, /* 0x94 */
|
||||
0x2022, /* 0x95 */
|
||||
0x2013, /* 0x96 */
|
||||
0x2014, /* 0x97 */
|
||||
0x02DC, /* 0x98 */
|
||||
0x2122, /* 0x99 */
|
||||
0x0161, /* 0x9A */
|
||||
0x203A, /* 0x9B */
|
||||
0x0153, /* 0x9C */
|
||||
0xFFFD, /* 0x9D */
|
||||
0x017E, /* 0x9E */
|
||||
0x0178, /* 0x9F */
|
||||
};
|
||||
|
||||
int guac_iconv(guac_iconv_read* reader, const char** input, int in_remaining,
|
||||
guac_iconv_write* writer, char** output, int out_remaining) {
|
||||
|
||||
while (in_remaining > 0 && out_remaining > 0) {
|
||||
|
||||
int value;
|
||||
const char* read_start;
|
||||
char* write_start;
|
||||
|
||||
/* Read character */
|
||||
read_start = *input;
|
||||
value = reader(input, in_remaining);
|
||||
in_remaining -= *input - read_start;
|
||||
|
||||
/* Write character */
|
||||
write_start = *output;
|
||||
writer(output, out_remaining, value);
|
||||
out_remaining -= *output - write_start;
|
||||
|
||||
/* Stop if null terminator reached */
|
||||
if (value == 0)
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Null terminator not reached */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF8(const char** input, int remaining) {
|
||||
|
||||
int value;
|
||||
|
||||
*input += guac_utf8_read(*input, remaining, &value);
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF16(const char** input, int remaining) {
|
||||
|
||||
int value;
|
||||
|
||||
/* Bail if not enough data */
|
||||
if (remaining < 2)
|
||||
return 0;
|
||||
|
||||
/* Read two bytes as integer */
|
||||
value = *((uint16_t*) *input);
|
||||
*input += 2;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_CP1252(const char** input, int remaining) {
|
||||
|
||||
int value = *((unsigned char*) *input);
|
||||
|
||||
/* Replace value with exception if not identical to ISO-8859-1 */
|
||||
if (value >= 0x80 && value <= 0x9F)
|
||||
value = __GUAC_RDP_CP1252_CODEPOINT[value - 0x80];
|
||||
|
||||
(*input)++;
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_ISO8859_1(const char** input, int remaining) {
|
||||
|
||||
int value = *((unsigned char*) *input);
|
||||
|
||||
(*input)++;
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF8(char** output, int remaining, int value) {
|
||||
*output += guac_utf8_write(value, *output, remaining);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF16(char** output, int remaining, int value) {
|
||||
|
||||
/* Bail if not enough data */
|
||||
if (remaining < 2)
|
||||
return;
|
||||
|
||||
/* Write two bytes as integer */
|
||||
*((uint16_t*) *output) = value;
|
||||
*output += 2;
|
||||
|
||||
}
|
||||
|
||||
void GUAC_WRITE_CP1252(char** output, int remaining, int value) {
|
||||
|
||||
/* If not in ISO-8859-1 part of CP1252, check lookup table */
|
||||
if ((value >= 0x80 && value <= 0x9F) || value > 0xFF) {
|
||||
|
||||
int i;
|
||||
int replacement_value = '?';
|
||||
const int* codepoint = __GUAC_RDP_CP1252_CODEPOINT;
|
||||
|
||||
/* Search lookup table for value */
|
||||
for (i=0x80; i<=0x9F; i++, codepoint++) {
|
||||
if (*codepoint == value) {
|
||||
replacement_value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace value with discovered value (or question mark) */
|
||||
value = replacement_value;
|
||||
|
||||
}
|
||||
|
||||
*((unsigned char*) *output) = (unsigned char) value;
|
||||
(*output)++;
|
||||
}
|
||||
|
||||
void GUAC_WRITE_ISO8859_1(char** output, int remaining, int value) {
|
||||
|
||||
/* Translate to question mark if out of range */
|
||||
if (value > 0xFF)
|
||||
value = '?';
|
||||
|
||||
*((unsigned char*) *output) = (unsigned char) value;
|
||||
(*output)++;
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_io.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int guac_common_write(int fd, void* buffer, int length) {
|
||||
|
||||
unsigned char* bytes = (unsigned char*) buffer;
|
||||
|
||||
while (length > 0) {
|
||||
|
||||
/* Attempt write */
|
||||
int bytes_written = write(fd, bytes, length);
|
||||
if (bytes_written < 0)
|
||||
return bytes_written;
|
||||
|
||||
/* Update buffer */
|
||||
length -= bytes_written;
|
||||
bytes += bytes_written;
|
||||
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_read(int fd, void* buffer, int length) {
|
||||
|
||||
unsigned char* bytes = (unsigned char*) buffer;
|
||||
|
||||
while (length > 0) {
|
||||
|
||||
/* Attempt read */
|
||||
int bytes_read = read(fd, bytes, length);
|
||||
if (bytes_read < 0)
|
||||
return bytes_read;
|
||||
|
||||
/* Update buffer */
|
||||
length -= bytes_read;
|
||||
bytes += bytes_read;
|
||||
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return length;
|
||||
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_IO_H
|
||||
#define __GUAC_COMMON_IO_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Writes absolutely all bytes from within the given buffer, returning an error
|
||||
* only if the required writes fail.
|
||||
*
|
||||
* @param fd The file descriptor to write to.
|
||||
* @param buffer The buffer containing the data to write.
|
||||
* @param length The number of bytes to write.
|
||||
* @return The number of bytes written, or a value less than zero if an error
|
||||
* occurs.
|
||||
*/
|
||||
int guac_common_write(int fd, void* buffer, int length);
|
||||
|
||||
/**
|
||||
* Reads enough bytes to fill the given buffer, returning an error only if the
|
||||
* required reads fail.
|
||||
*
|
||||
* @param fd The file descriptor to read from.
|
||||
* @param buffer The buffer to read data into.
|
||||
* @param length The number of bytes to read.
|
||||
* @return The number of bytes read, or a value less than zero if an error
|
||||
* occurs.
|
||||
*/
|
||||
int guac_common_read(int fd, void* buffer, int length);
|
||||
|
||||
#endif
|
||||
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUAC_COMMON_POINTER_CURSOR_H
|
||||
#define _GUAC_COMMON_POINTER_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_common_pointer_cursor_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_common_pointer_cursor_format;
|
||||
|
||||
/**
|
||||
* Embedded mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_common_pointer_cursor[];
|
||||
|
||||
/**
|
||||
* Set the cursor of the remote display to the embedded cursor graphic.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
*/
|
||||
void guac_common_set_pointer_cursor(guac_client* client);
|
||||
|
||||
#endif
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_rect.h"
|
||||
|
||||
void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height) {
|
||||
rect->x = x;
|
||||
rect->y = y;
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
}
|
||||
|
||||
void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) {
|
||||
|
||||
/* Calculate extents of existing dirty rect */
|
||||
int left = rect->x;
|
||||
int top = rect->y;
|
||||
int right = left + rect->width;
|
||||
int bottom = top + rect->height;
|
||||
|
||||
/* Calculate missing extents of given new rect */
|
||||
int min_left = min->x;
|
||||
int min_top = min->y;
|
||||
int min_right = min_left + min->width;
|
||||
int min_bottom = min_top + min->height;
|
||||
|
||||
/* Update minimums */
|
||||
if (min_left < left) left = min_left;
|
||||
if (min_top < top) top = min_top;
|
||||
if (min_right > right) right = min_right;
|
||||
if (min_bottom > bottom) bottom = min_bottom;
|
||||
|
||||
/* Commit rect */
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) {
|
||||
|
||||
/* Calculate extents of existing dirty rect */
|
||||
int left = rect->x;
|
||||
int top = rect->y;
|
||||
int right = left + rect->width;
|
||||
int bottom = top + rect->height;
|
||||
|
||||
/* Calculate missing extents of given new rect */
|
||||
int max_left = max->x;
|
||||
int max_top = max->y;
|
||||
int max_right = max_left + max->width;
|
||||
int max_bottom = max_top + max->height;
|
||||
|
||||
/* Update maximums */
|
||||
if (max_left > left) left = max_left;
|
||||
if (max_top > top) top = max_top;
|
||||
if (max_right < right) right = max_right;
|
||||
if (max_bottom < bottom) bottom = max_bottom;
|
||||
|
||||
/* Commit rect */
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_RECT_H
|
||||
#define __GUAC_COMMON_RECT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Simple representation of a rectangle, having a defined corner and dimensions.
|
||||
*/
|
||||
typedef struct guac_common_rect {
|
||||
|
||||
/**
|
||||
* The X coordinate of the upper-left corner of this rectangle.
|
||||
*/
|
||||
int x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the upper-left corner of this rectangle.
|
||||
*/
|
||||
int y;
|
||||
|
||||
/**
|
||||
* The width of this rectangle.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of this rectangle.
|
||||
*/
|
||||
int height;
|
||||
|
||||
} guac_common_rect;
|
||||
|
||||
/**
|
||||
* Initialize the given rect with the given coordinates and dimensions.
|
||||
*
|
||||
* @param rect The rect to initialize.
|
||||
* @param x The X coordinate of the upper-left corner of the rect.
|
||||
* @param y The Y coordinate of the upper-left corner of the rect.
|
||||
* @param width The width of the rect.
|
||||
* @param height The height of the rect.
|
||||
*/
|
||||
void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* Extend the given rect such that it contains at least the specified minimum
|
||||
* rect.
|
||||
*
|
||||
* @param rect The rect to extend.
|
||||
* @param min The minimum area which must be contained within the given rect.
|
||||
*/
|
||||
void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min);
|
||||
|
||||
/**
|
||||
* Collapse the given rect such that it exists only within the given maximum
|
||||
* rect.
|
||||
*
|
||||
* @param rect The rect to extend.
|
||||
* @param max The maximum area in which the given rect can exist.
|
||||
*/
|
||||
void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max);
|
||||
|
||||
#endif
|
||||
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_STRING_H
|
||||
#define __GUAC_COMMON_STRING_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Counts the number of occurrences of a given character in a string.
|
||||
*
|
||||
* @param string The string to count occurrences within.
|
||||
* @param c The character to count occurrences of.
|
||||
* @return The number of occurrences.
|
||||
*/
|
||||
int guac_count_occurrences(const char* string, char c);
|
||||
|
||||
/**
|
||||
* Splits a string into a newly-allocated array of strings. The array itself
|
||||
* and each string within the array will eventually need to be freed. The array
|
||||
* is NULL-terminated.
|
||||
*
|
||||
* @param string The string to split.
|
||||
* @param delim The character which separates individual substrings within the
|
||||
* given string.
|
||||
* @return A newly-allocated, NULL-terminated array of strings.
|
||||
*/
|
||||
char** guac_split(const char* string, char delim);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __GUAC_COMMON_SURFACE_H
|
||||
#define __GUAC_COMMON_SURFACE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_rect.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
/**
|
||||
* The maximum number of updates to allow within the PNG queue.
|
||||
*/
|
||||
#define GUAC_COMMON_SURFACE_QUEUE_SIZE 256
|
||||
|
||||
/**
|
||||
* Representation of a PNG update, having a rectangle of image data (stored
|
||||
* elsewhere) and a flushed/not-flushed state.
|
||||
*/
|
||||
typedef struct guac_common_surface_png_rect {
|
||||
|
||||
/**
|
||||
* Whether this rectangle has been flushed.
|
||||
*/
|
||||
int flushed;
|
||||
|
||||
/**
|
||||
* The rectangle containing the PNG update.
|
||||
*/
|
||||
guac_common_rect rect;
|
||||
|
||||
} guac_common_surface_png_rect;
|
||||
|
||||
/**
|
||||
* Surface which backs a Guacamole buffer or layer, automatically
|
||||
* combining updates when possible.
|
||||
*/
|
||||
typedef struct guac_common_surface {
|
||||
|
||||
/**
|
||||
* The layer this surface will draw to.
|
||||
*/
|
||||
const guac_layer* layer;
|
||||
|
||||
/**
|
||||
* The socket to send instructions on when flushing.
|
||||
*/
|
||||
guac_socket* socket;
|
||||
|
||||
/**
|
||||
* The width of this layer, in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of this layer, in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The size of each image row, in bytes.
|
||||
*/
|
||||
int stride;
|
||||
|
||||
/**
|
||||
* The underlying buffer of the Cairo surface.
|
||||
*/
|
||||
unsigned char* buffer;
|
||||
|
||||
/**
|
||||
* Non-zero if this surface is dirty and needs to be flushed, 0 otherwise.
|
||||
*/
|
||||
int dirty;
|
||||
|
||||
/**
|
||||
* The dirty rectangle.
|
||||
*/
|
||||
guac_common_rect dirty_rect;
|
||||
|
||||
/**
|
||||
* Whether the surface actually exists on the client.
|
||||
*/
|
||||
int realized;
|
||||
|
||||
/**
|
||||
* The bounding rectangle.
|
||||
*/
|
||||
guac_common_rect bounds_rect;
|
||||
|
||||
/**
|
||||
* The number of updates in the PNG queue.
|
||||
*/
|
||||
int png_queue_length;
|
||||
|
||||
/**
|
||||
* All queued PNG updates.
|
||||
*/
|
||||
guac_common_surface_png_rect png_queue[GUAC_COMMON_SURFACE_QUEUE_SIZE];
|
||||
|
||||
} guac_common_surface;
|
||||
|
||||
/**
|
||||
* Allocates a new guac_common_surface, assigning it to the given layer.
|
||||
*
|
||||
* @param socket The socket to send instructions on when flushing.
|
||||
* @param layer The layer to associate with the new surface.
|
||||
* @param w The width of the surface.
|
||||
* @param h The height of the surface.
|
||||
* @return A newly-allocated guac_common_surface.
|
||||
*/
|
||||
guac_common_surface* guac_common_surface_alloc(guac_socket* socket, const guac_layer* layer, int w, int h);
|
||||
|
||||
/**
|
||||
* Frees the given guac_common_surface. Beware that this will NOT free any
|
||||
* associated layers, which must be freed manually.
|
||||
*
|
||||
* @param surface The surface to free.
|
||||
*/
|
||||
void guac_common_surface_free(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Resizes the given surface to the given size.
|
||||
*
|
||||
* @param surface The surface to resize.
|
||||
* @param w The width of the surface.
|
||||
* @param h The height of the surface.
|
||||
*/
|
||||
void guac_common_surface_resize(guac_common_surface* surface, int w, int h);
|
||||
|
||||
/**
|
||||
* Draws the given data to the given guac_common_surface.
|
||||
*
|
||||
* @param surface The surface to draw to.
|
||||
* @param x The X coordinate of the draw location.
|
||||
* @param y The Y coordinate of the draw location.
|
||||
* @param src The Cairo surface to retrieve data from.
|
||||
*/
|
||||
void guac_common_surface_draw(guac_common_surface* surface, int x, int y, cairo_surface_t* src);
|
||||
|
||||
/**
|
||||
* Paints to the given guac_common_surface using the given data as a stencil,
|
||||
* filling opaque regions with the specified color, and leaving transparent
|
||||
* regions untouched.
|
||||
*
|
||||
* @param surface The surface to draw to.
|
||||
* @param x The X coordinate of the draw location.
|
||||
* @param y The Y coordinate of the draw location.
|
||||
* @param src The Cairo surface to retrieve data from.
|
||||
* @param red The red component of the fill color.
|
||||
* @param green The green component of the fill color.
|
||||
* @param blue The blue component of the fill color.
|
||||
*/
|
||||
void guac_common_surface_paint(guac_common_surface* surface, int x, int y, cairo_surface_t* src,
|
||||
int red, int green, int blue);
|
||||
|
||||
/**
|
||||
* Copies a rectangle of data between two surfaces.
|
||||
*
|
||||
* @param src The source surface.
|
||||
* @param sx The X coordinate of the upper-left corner of the source rect.
|
||||
* @param sy The Y coordinate of the upper-left corner of the source rect.
|
||||
* @param w The width of the source rect.
|
||||
* @param h The height of the source rect.
|
||||
* @param dst The destination surface.
|
||||
* @param dx The X coordinate of the upper-left corner of the destination rect.
|
||||
* @param dy The Y coordinate of the upper-left corner of the destination rect.
|
||||
*/
|
||||
void guac_common_surface_copy(guac_common_surface* src, int sx, int sy, int w, int h,
|
||||
guac_common_surface* dst, int dx, int dy);
|
||||
|
||||
/**
|
||||
* Transfers a rectangle of data between two surfaces.
|
||||
*
|
||||
* @param src The source surface.
|
||||
* @param sx The X coordinate of the upper-left corner of the source rect.
|
||||
* @param sy The Y coordinate of the upper-left corner of the source rect.
|
||||
* @param w The width of the source rect.
|
||||
* @param h The height of the source rect.
|
||||
* @param op The transfer function.
|
||||
* @param dst The destination surface.
|
||||
* @param dx The X coordinate of the upper-left corner of the destination rect.
|
||||
* @param dy The Y coordinate of the upper-left corner of the destination rect.
|
||||
*/
|
||||
void guac_common_surface_transfer(guac_common_surface* src, int sx, int sy, int w, int h,
|
||||
guac_transfer_function op, guac_common_surface* dst, int dx, int dy);
|
||||
|
||||
/**
|
||||
* Draws a solid color rectangle at the given coordinates on the given surface.
|
||||
*
|
||||
* @param surface The surface to draw upon.
|
||||
* @param x The X coordinate of the upper-left corner of the rectangle.
|
||||
* @param y The Y coordinate of the upper-left corner of the rectangle.
|
||||
* @param w The width of the rectangle.
|
||||
* @param h The height of the rectangle.
|
||||
* @param red The red component of the color of the rectangle.
|
||||
* @param green The green component of the color of the rectangle.
|
||||
* @param blue The blue component of the color of the rectangle.
|
||||
*/
|
||||
void guac_common_surface_rect(guac_common_surface* surface,
|
||||
int x, int y, int w, int h,
|
||||
int red, int green, int blue);
|
||||
|
||||
/**
|
||||
* Given the coordinates and dimensions of a rectangle, clips all future
|
||||
* operations within that rectangle.
|
||||
*
|
||||
* @param surface The surface whose clipping rectangle should be changed.
|
||||
* @param x The X coordinate of the upper-left corner of the bounding rectangle.
|
||||
* @param y The Y coordinate of the upper-left corner of the bounding rectangle.
|
||||
* @param w The width of the bounding rectangle.
|
||||
* @param h The height of the bounding rectangle.
|
||||
*/
|
||||
void guac_common_surface_clip(guac_common_surface* surface, int x, int y, int w, int h);
|
||||
|
||||
/**
|
||||
* Resets the clipping rectangle, allowing drawing operations throughout the
|
||||
* entire surface.
|
||||
*
|
||||
* @param surface The surface whose clipping rectangle should be reset.
|
||||
*/
|
||||
void guac_common_surface_reset_clip(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Flushes the given surface, drawing any pending operations on the remote
|
||||
* display.
|
||||
*
|
||||
* @param surface The surface to flush.
|
||||
*/
|
||||
void guac_common_surface_flush(guac_common_surface* surface);
|
||||
|
||||
/**
|
||||
* Schedules a deferred flush of the given surface. This will not immediately
|
||||
* flush the surface to the client. Instead, the result of the flush is
|
||||
* added to a queue which is reinspected and combined (if possible) with other
|
||||
* deferred flushes during the call to guac_common_surface_flush().
|
||||
*
|
||||
* @param surface The surface to flush.
|
||||
*/
|
||||
void guac_common_surface_flush_deferred(guac_common_surface* surface);
|
||||
|
||||
#endif
|
||||
|
98
src/common/ibar_cursor.c
Normal file
98
src/common/ibar_cursor.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
#define U 0x80,0x80,0x80,0xFF
|
||||
#define O 0xFF,0xFF,0xFF,0xFF
|
||||
#define _ 0x00,0x00,0x00,0x00
|
||||
|
||||
/* Dimensions */
|
||||
const int guac_common_ibar_cursor_width = 7;
|
||||
const int guac_common_ibar_cursor_height = 16;
|
||||
|
||||
/* Format */
|
||||
const cairo_format_t guac_common_ibar_cursor_format = CAIRO_FORMAT_ARGB32;
|
||||
const int guac_common_ibar_cursor_stride = 28;
|
||||
|
||||
/* Embedded I-bar graphic */
|
||||
unsigned char guac_common_ibar_cursor[] = {
|
||||
|
||||
X,X,X,X,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,O,X,X,X,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
X,X,X,O,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,X,X,X,X
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_ibar_cursor(guac_user* user) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
|
||||
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
|
||||
guac_common_ibar_cursor,
|
||||
guac_common_ibar_cursor_format,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height,
|
||||
guac_common_ibar_cursor_stride);
|
||||
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
guac_protocol_send_cursor(socket, 0, 0, cursor,
|
||||
guac_common_ibar_cursor_width / 2,
|
||||
guac_common_ibar_cursor_height / 2,
|
||||
guac_common_ibar_cursor_width,
|
||||
guac_common_ibar_cursor_height);
|
||||
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic built-in I-bar.");
|
||||
|
||||
}
|
||||
|
306
src/common/iconv.c
Normal file
306
src/common/iconv.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/iconv.h"
|
||||
|
||||
#include <guacamole/unicode.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Lookup table for Unicode code points, indexed by CP-1252 codepoint.
|
||||
*/
|
||||
const static int __GUAC_RDP_CP1252_CODEPOINT[32] = {
|
||||
0x20AC, /* 0x80 */
|
||||
0xFFFD, /* 0x81 */
|
||||
0x201A, /* 0x82 */
|
||||
0x0192, /* 0x83 */
|
||||
0x201E, /* 0x84 */
|
||||
0x2026, /* 0x85 */
|
||||
0x2020, /* 0x86 */
|
||||
0x2021, /* 0x87 */
|
||||
0x02C6, /* 0x88 */
|
||||
0x2030, /* 0x89 */
|
||||
0x0160, /* 0x8A */
|
||||
0x2039, /* 0x8B */
|
||||
0x0152, /* 0x8C */
|
||||
0xFFFD, /* 0x8D */
|
||||
0x017D, /* 0x8E */
|
||||
0xFFFD, /* 0x8F */
|
||||
0xFFFD, /* 0x90 */
|
||||
0x2018, /* 0x91 */
|
||||
0x2019, /* 0x92 */
|
||||
0x201C, /* 0x93 */
|
||||
0x201D, /* 0x94 */
|
||||
0x2022, /* 0x95 */
|
||||
0x2013, /* 0x96 */
|
||||
0x2014, /* 0x97 */
|
||||
0x02DC, /* 0x98 */
|
||||
0x2122, /* 0x99 */
|
||||
0x0161, /* 0x9A */
|
||||
0x203A, /* 0x9B */
|
||||
0x0153, /* 0x9C */
|
||||
0xFFFD, /* 0x9D */
|
||||
0x017E, /* 0x9E */
|
||||
0x0178, /* 0x9F */
|
||||
};
|
||||
|
||||
int guac_iconv(guac_iconv_read* reader, const char** input, int in_remaining,
|
||||
guac_iconv_write* writer, char** output, int out_remaining) {
|
||||
|
||||
while (in_remaining > 0 && out_remaining > 0) {
|
||||
|
||||
int value;
|
||||
const char* read_start;
|
||||
char* write_start;
|
||||
|
||||
/* Read character */
|
||||
read_start = *input;
|
||||
value = reader(input, in_remaining);
|
||||
in_remaining -= *input - read_start;
|
||||
|
||||
/* Write character */
|
||||
write_start = *output;
|
||||
writer(output, out_remaining, value);
|
||||
out_remaining -= *output - write_start;
|
||||
|
||||
/* Stop if null terminator reached */
|
||||
if (value == 0)
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Null terminator not reached */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF8(const char** input, int remaining) {
|
||||
|
||||
int value;
|
||||
|
||||
*input += guac_utf8_read(*input, remaining, &value);
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF16(const char** input, int remaining) {
|
||||
|
||||
int value;
|
||||
|
||||
/* Bail if not enough data */
|
||||
if (remaining < 2)
|
||||
return 0;
|
||||
|
||||
/* Read two bytes as integer */
|
||||
value = *((uint16_t*) *input);
|
||||
*input += 2;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_CP1252(const char** input, int remaining) {
|
||||
|
||||
int value = *((unsigned char*) *input);
|
||||
|
||||
/* Replace value with exception if not identical to ISO-8859-1 */
|
||||
if (value >= 0x80 && value <= 0x9F)
|
||||
value = __GUAC_RDP_CP1252_CODEPOINT[value - 0x80];
|
||||
|
||||
(*input)++;
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_ISO8859_1(const char** input, int remaining) {
|
||||
|
||||
int value = *((unsigned char*) *input);
|
||||
|
||||
(*input)++;
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given reader function, automatically normalizing newline
|
||||
* sequences as Unix-style newline characters ('\n'). All other charaters are
|
||||
* read verbatim.
|
||||
*
|
||||
* @param reader
|
||||
* The reader to use to read the given character.
|
||||
*
|
||||
* @param input
|
||||
* Pointer to the location within the input buffer that the next character
|
||||
* should be read from.
|
||||
*
|
||||
* @param remaining
|
||||
* The number of bytes remaining in the input buffer.
|
||||
*
|
||||
* @return
|
||||
* The codepoint that was read, or zero if the end of the input string has
|
||||
* been reached.
|
||||
*/
|
||||
static int guac_iconv_read_normalized(guac_iconv_read* reader,
|
||||
const char** input, int remaining) {
|
||||
|
||||
/* Read requested character */
|
||||
const char* input_start = *input;
|
||||
int value = reader(input, remaining);
|
||||
|
||||
/* Automatically translate CRLF pairs to simple newlines */
|
||||
if (value == '\r') {
|
||||
|
||||
/* Peek ahead by one character, adjusting remaining bytes relative to
|
||||
* last read */
|
||||
int peek_remaining = remaining - (*input - input_start);
|
||||
const char* peek_input = *input;
|
||||
int peek_value = reader(&peek_input, peek_remaining);
|
||||
|
||||
/* Consider read value to be a newline if we have encountered a "\r\n"
|
||||
* (CRLF) pair */
|
||||
if (peek_value == '\n') {
|
||||
value = '\n';
|
||||
*input = peek_input;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF8_NORMALIZED(const char** input, int remaining) {
|
||||
return guac_iconv_read_normalized(GUAC_READ_UTF8, input, remaining);
|
||||
}
|
||||
|
||||
int GUAC_READ_UTF16_NORMALIZED(const char** input, int remaining) {
|
||||
return guac_iconv_read_normalized(GUAC_READ_UTF16, input, remaining);
|
||||
}
|
||||
|
||||
int GUAC_READ_CP1252_NORMALIZED(const char** input, int remaining) {
|
||||
return guac_iconv_read_normalized(GUAC_READ_CP1252, input, remaining);
|
||||
}
|
||||
|
||||
int GUAC_READ_ISO8859_1_NORMALIZED(const char** input, int remaining) {
|
||||
return guac_iconv_read_normalized(GUAC_READ_ISO8859_1, input, remaining);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF8(char** output, int remaining, int value) {
|
||||
*output += guac_utf8_write(value, *output, remaining);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF16(char** output, int remaining, int value) {
|
||||
|
||||
/* Bail if not enough data */
|
||||
if (remaining < 2)
|
||||
return;
|
||||
|
||||
/* Write two bytes as integer */
|
||||
*((uint16_t*) *output) = value;
|
||||
*output += 2;
|
||||
|
||||
}
|
||||
|
||||
void GUAC_WRITE_CP1252(char** output, int remaining, int value) {
|
||||
|
||||
/* If not in ISO-8859-1 part of CP1252, check lookup table */
|
||||
if ((value >= 0x80 && value <= 0x9F) || value > 0xFF) {
|
||||
|
||||
int i;
|
||||
int replacement_value = '?';
|
||||
const int* codepoint = __GUAC_RDP_CP1252_CODEPOINT;
|
||||
|
||||
/* Search lookup table for value */
|
||||
for (i=0x80; i<=0x9F; i++, codepoint++) {
|
||||
if (*codepoint == value) {
|
||||
replacement_value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace value with discovered value (or question mark) */
|
||||
value = replacement_value;
|
||||
|
||||
}
|
||||
|
||||
*((unsigned char*) *output) = (unsigned char) value;
|
||||
(*output)++;
|
||||
}
|
||||
|
||||
void GUAC_WRITE_ISO8859_1(char** output, int remaining, int value) {
|
||||
|
||||
/* Translate to question mark if out of range */
|
||||
if (value > 0xFF)
|
||||
value = '?';
|
||||
|
||||
*((unsigned char*) *output) = (unsigned char) value;
|
||||
(*output)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given writer function, automatically writing newline characters
|
||||
* ('\n') as CRLF ("\r\n"). All other charaters are written verbatim.
|
||||
*
|
||||
* @param writer
|
||||
* The writer to use to write the given character.
|
||||
*
|
||||
* @param output
|
||||
* Pointer to the location within the output buffer that the next character
|
||||
* should be written.
|
||||
*
|
||||
* @param remaining
|
||||
* The number of bytes remaining in the output buffer.
|
||||
*
|
||||
* @param value
|
||||
* The codepoint of the character to write.
|
||||
*/
|
||||
static void guac_iconv_write_crlf(guac_iconv_write* writer, char** output,
|
||||
int remaining, int value) {
|
||||
|
||||
if (value != '\n') {
|
||||
writer(output, remaining, value);
|
||||
return;
|
||||
}
|
||||
|
||||
char* output_start = *output;
|
||||
writer(output, remaining, '\r');
|
||||
|
||||
remaining -= *output - output_start;
|
||||
if (remaining > 0)
|
||||
writer(output, remaining, '\n');
|
||||
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF8_CRLF(char** output, int remaining, int value) {
|
||||
guac_iconv_write_crlf(GUAC_WRITE_UTF8, output, remaining, value);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_UTF16_CRLF(char** output, int remaining, int value) {
|
||||
guac_iconv_write_crlf(GUAC_WRITE_UTF16, output, remaining, value);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_CP1252_CRLF(char** output, int remaining, int value) {
|
||||
guac_iconv_write_crlf(GUAC_WRITE_CP1252, output, remaining, value);
|
||||
}
|
||||
|
||||
void GUAC_WRITE_ISO8859_1_CRLF(char** output, int remaining, int value) {
|
||||
guac_iconv_write_crlf(GUAC_WRITE_ISO8859_1, output, remaining, value);
|
||||
}
|
||||
|
68
src/common/io.c
Normal file
68
src/common/io.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/io.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int guac_common_write(int fd, void* buffer, int length) {
|
||||
|
||||
unsigned char* bytes = (unsigned char*) buffer;
|
||||
|
||||
while (length > 0) {
|
||||
|
||||
/* Attempt write */
|
||||
int bytes_written = write(fd, bytes, length);
|
||||
if (bytes_written < 0)
|
||||
return bytes_written;
|
||||
|
||||
/* Update buffer */
|
||||
length -= bytes_written;
|
||||
bytes += bytes_written;
|
||||
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_read(int fd, void* buffer, int length) {
|
||||
|
||||
unsigned char* bytes = (unsigned char*) buffer;
|
||||
|
||||
while (length > 0) {
|
||||
|
||||
/* Attempt read */
|
||||
int bytes_read = read(fd, bytes, length);
|
||||
if (bytes_read < 0)
|
||||
return bytes_read;
|
||||
|
||||
/* Update buffer */
|
||||
length -= bytes_read;
|
||||
bytes += bytes_read;
|
||||
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return length;
|
||||
|
||||
}
|
||||
|
180
src/common/json.c
Normal file
180
src/common/json.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/json.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
void guac_common_json_flush(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* If JSON buffer is non-empty, write contents to blob and reset */
|
||||
if (json_state->size > 0) {
|
||||
guac_protocol_send_blob(user->socket, stream,
|
||||
json_state->buffer, json_state->size);
|
||||
|
||||
/* Reset JSON buffer size */
|
||||
json_state->size = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* buffer, int length) {
|
||||
|
||||
int blob_written = 0;
|
||||
|
||||
/*
|
||||
* Append to and flush the JSON buffer as necessary to write the given
|
||||
* data
|
||||
*/
|
||||
while (length > 0) {
|
||||
|
||||
/* Ensure provided data does not exceed size of buffer */
|
||||
int blob_length = length;
|
||||
if (blob_length > sizeof(json_state->buffer))
|
||||
blob_length = sizeof(json_state->buffer);
|
||||
|
||||
/* Flush if more room is needed */
|
||||
if (json_state->size + blob_length > sizeof(json_state->buffer)) {
|
||||
guac_common_json_flush(user, stream, json_state);
|
||||
blob_written = 1;
|
||||
}
|
||||
|
||||
/* Append data to JSON buffer */
|
||||
memcpy(json_state->buffer + json_state->size,
|
||||
buffer, blob_length);
|
||||
|
||||
json_state->size += blob_length;
|
||||
|
||||
/* Advance to next blob of data */
|
||||
buffer += blob_length;
|
||||
length -= blob_length;
|
||||
|
||||
}
|
||||
|
||||
return blob_written;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write_string(guac_user* user,
|
||||
guac_stream* stream, guac_common_json_state* json_state,
|
||||
const char* str) {
|
||||
|
||||
int blob_written = 0;
|
||||
|
||||
/* Write starting quote */
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\"", 1);
|
||||
|
||||
/* Write given string, escaping as necessary */
|
||||
const char* current = str;
|
||||
for (; *current != '\0'; current++) {
|
||||
|
||||
/* Escape all quotes and back-slashes */
|
||||
if (*current == '"' || *current == '\\') {
|
||||
|
||||
/* Write any string content up to current character */
|
||||
if (current != str)
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, str, current - str);
|
||||
|
||||
/* Escape the character that was just read */
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\\", 1);
|
||||
|
||||
/* Reset string */
|
||||
str = current;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write any remaining string content */
|
||||
if (current != str)
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, str, current - str);
|
||||
|
||||
/* Write ending quote */
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, "\"", 1);
|
||||
|
||||
return blob_written;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_write_property(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state, const char* name,
|
||||
const char* value) {
|
||||
|
||||
int blob_written = 0;
|
||||
|
||||
/* Write leading comma if not first property */
|
||||
if (json_state->properties_written != 0)
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, ",", 1);
|
||||
|
||||
/* Write property name */
|
||||
blob_written |= guac_common_json_write_string(user, stream,
|
||||
json_state, name);
|
||||
|
||||
/* Separate name from value with colon */
|
||||
blob_written |= guac_common_json_write(user, stream,
|
||||
json_state, ":", 1);
|
||||
|
||||
/* Write property value */
|
||||
blob_written |= guac_common_json_write_string(user, stream,
|
||||
json_state, value);
|
||||
|
||||
json_state->properties_written++;
|
||||
|
||||
return blob_written;
|
||||
|
||||
}
|
||||
|
||||
void guac_common_json_begin_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* Init JSON state */
|
||||
json_state->size = 0;
|
||||
json_state->properties_written = 0;
|
||||
|
||||
/* Write leading brace - no blob can possibly be written by this */
|
||||
assert(!guac_common_json_write(user, stream, json_state, "{", 1));
|
||||
|
||||
}
|
||||
|
||||
int guac_common_json_end_object(guac_user* user, guac_stream* stream,
|
||||
guac_common_json_state* json_state) {
|
||||
|
||||
/* Write final brace of JSON object */
|
||||
return guac_common_json_write(user, stream, json_state, "}", 1);
|
||||
|
||||
}
|
||||
|
@ -1,27 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "guac_list.h"
|
||||
#include "common/list.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
@ -1,23 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -27,6 +24,7 @@
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
@ -63,9 +61,10 @@ unsigned char guac_common_pointer_cursor[] = {
|
||||
|
||||
};
|
||||
|
||||
void guac_common_set_pointer_cursor(guac_client* client) {
|
||||
void guac_common_set_pointer_cursor(guac_user* user) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_client* client = user->client;
|
||||
guac_socket* socket = user->socket;
|
||||
|
||||
/* Draw to buffer */
|
||||
guac_layer* cursor = guac_client_alloc_buffer(client);
|
||||
@ -77,7 +76,8 @@ void guac_common_set_pointer_cursor(guac_client* client) {
|
||||
guac_common_pointer_cursor_height,
|
||||
guac_common_pointer_cursor_stride);
|
||||
|
||||
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor, 0, 0, graphic);
|
||||
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Set cursor */
|
||||
@ -89,5 +89,8 @@ void guac_common_set_pointer_cursor(guac_client* client) {
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Client cursor image set to generic built-in pointer.");
|
||||
|
||||
}
|
||||
|
266
src/common/rect.c
Normal file
266
src/common/rect.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height) {
|
||||
rect->x = x;
|
||||
rect->y = y;
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
}
|
||||
|
||||
void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) {
|
||||
|
||||
/* Calculate extents of existing dirty rect */
|
||||
int left = rect->x;
|
||||
int top = rect->y;
|
||||
int right = left + rect->width;
|
||||
int bottom = top + rect->height;
|
||||
|
||||
/* Calculate missing extents of given new rect */
|
||||
int min_left = min->x;
|
||||
int min_top = min->y;
|
||||
int min_right = min_left + min->width;
|
||||
int min_bottom = min_top + min->height;
|
||||
|
||||
/* Update minimums */
|
||||
if (min_left < left) left = min_left;
|
||||
if (min_top < top) top = min_top;
|
||||
if (min_right > right) right = min_right;
|
||||
if (min_bottom > bottom) bottom = min_bottom;
|
||||
|
||||
/* Commit rect */
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
}
|
||||
|
||||
void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) {
|
||||
|
||||
/* Calculate extents of existing dirty rect */
|
||||
int left = rect->x;
|
||||
int top = rect->y;
|
||||
int right = left + rect->width;
|
||||
int bottom = top + rect->height;
|
||||
|
||||
/* Calculate missing extents of given new rect */
|
||||
int max_left = max->x;
|
||||
int max_top = max->y;
|
||||
int max_right = max_left + max->width;
|
||||
int max_bottom = max_top + max->height;
|
||||
|
||||
/* Update maximums */
|
||||
if (max_left > left) left = max_left;
|
||||
if (max_top > top) top = max_top;
|
||||
if (max_right < right) right = max_right;
|
||||
if (max_bottom < bottom) bottom = max_bottom;
|
||||
|
||||
/* Commit rect */
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
}
|
||||
|
||||
int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect,
|
||||
const guac_common_rect* max_rect) {
|
||||
|
||||
/* Invalid cell_size received */
|
||||
if (cell_size <= 0)
|
||||
return -1;
|
||||
|
||||
/* Nothing to do */
|
||||
if (cell_size == 1)
|
||||
return 0;
|
||||
|
||||
/* Calculate how much the rectangle must be adjusted to fit within the
|
||||
* given cell size. */
|
||||
int dw = cell_size - rect->width % cell_size;
|
||||
int dh = cell_size - rect->height % cell_size;
|
||||
|
||||
int dx = dw / 2;
|
||||
int dy = dh / 2;
|
||||
|
||||
/* Set initial extents of adjusted rectangle. */
|
||||
int top = rect->y - dy;
|
||||
int left = rect->x - dx;
|
||||
int bottom = top + rect->height + dh;
|
||||
int right = left + rect->width + dw;
|
||||
|
||||
/* The max rectangle */
|
||||
int max_left = max_rect->x;
|
||||
int max_top = max_rect->y;
|
||||
int max_right = max_left + max_rect->width;
|
||||
int max_bottom = max_top + max_rect->height;
|
||||
|
||||
/* If the adjusted rectangle has sides beyond the max rectangle, or is larger
|
||||
* in any direction; shift or adjust the rectangle while trying to fit in
|
||||
* the grid */
|
||||
|
||||
/* Adjust left/right */
|
||||
if (right > max_right) {
|
||||
|
||||
/* shift to left */
|
||||
dw = right - max_right;
|
||||
right -= dw;
|
||||
left -= dw;
|
||||
|
||||
/* clamp left if too far */
|
||||
if (left < max_left) {
|
||||
left = max_left;
|
||||
}
|
||||
}
|
||||
else if (left < max_left) {
|
||||
|
||||
/* shift to right */
|
||||
dw = max_left - left;
|
||||
left += dw;
|
||||
right += dw;
|
||||
|
||||
/* clamp right if too far */
|
||||
if (right > max_right) {
|
||||
right = max_right;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust top/bottom */
|
||||
if (bottom > max_bottom) {
|
||||
|
||||
/* shift up */
|
||||
dh = bottom - max_bottom;
|
||||
bottom -= dh;
|
||||
top -= dh;
|
||||
|
||||
/* clamp top if too far */
|
||||
if (top < max_top) {
|
||||
top = max_top;
|
||||
}
|
||||
}
|
||||
else if (top < max_top) {
|
||||
|
||||
/* shift down */
|
||||
dh = max_top - top;
|
||||
top += dh;
|
||||
bottom += dh;
|
||||
|
||||
/* clamp bottom if too far */
|
||||
if (bottom > max_bottom) {
|
||||
bottom = max_bottom;
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit rect */
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_rect_intersects(const guac_common_rect* rect,
|
||||
const guac_common_rect* other) {
|
||||
|
||||
/* Empty (no intersection) */
|
||||
if (other->x + other->width < rect->x || rect->x + rect->width < other->x ||
|
||||
other->y + other->height < rect->y || rect->y + rect->height < other->y) {
|
||||
return 0;
|
||||
}
|
||||
/* Complete */
|
||||
else if (other->x <= rect->x && (other->x + other->width) >= (rect->x + rect->width) &&
|
||||
other->y <= rect->y && (other->y + other->height) >= (rect->y + rect->height)) {
|
||||
return 2;
|
||||
}
|
||||
/* Partial intersection */
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int guac_common_rect_clip_and_split(guac_common_rect* rect,
|
||||
const guac_common_rect* hole, guac_common_rect* split_rect) {
|
||||
|
||||
/* Only continue if the rectangles intersects */
|
||||
if (!guac_common_rect_intersects(rect, hole))
|
||||
return 0;
|
||||
|
||||
int top, left, bottom, right;
|
||||
|
||||
/* Clip and split top */
|
||||
if (rect->y < hole->y) {
|
||||
top = rect->y;
|
||||
left = rect->x;
|
||||
bottom = hole->y;
|
||||
right = rect->x + rect->width;
|
||||
guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
|
||||
|
||||
/* Re-initialize original rect */
|
||||
top = hole->y;
|
||||
bottom = rect->y + rect->height;
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clip and split left */
|
||||
else if (rect->x < hole->x) {
|
||||
top = rect->y;
|
||||
left = rect->x;
|
||||
bottom = rect->y + rect->height;
|
||||
right = hole->x;
|
||||
guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
|
||||
|
||||
/* Re-initialize original rect */
|
||||
left = hole->x;
|
||||
right = rect->x + rect->width;
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clip and split bottom */
|
||||
else if (rect->y + rect->height > hole->y + hole->height) {
|
||||
top = hole->y + hole->height;
|
||||
left = rect->x;
|
||||
bottom = rect->y + rect->height;
|
||||
right = rect->x + rect->width;
|
||||
guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
|
||||
|
||||
/* Re-initialize original rect */
|
||||
top = rect->y;
|
||||
bottom = hole->y + hole->height;
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clip and split right */
|
||||
else if (rect->x + rect->width > hole->x + hole->width) {
|
||||
top = rect->y;
|
||||
left = hole->x + hole->width;
|
||||
bottom = rect->y + rect->height;
|
||||
right = rect->x + rect->width;
|
||||
guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
|
||||
|
||||
/* Re-initialize original rect */
|
||||
left = rect->x;
|
||||
right = hole->x + hole->width;
|
||||
guac_common_rect_init(rect, left, top, right - left, bottom - top);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,28 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "guac_string.h"
|
||||
#include "common/string.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
2041
src/common/surface.c
Normal file
2041
src/common/surface.c
Normal file
File diff suppressed because it is too large
Load Diff
76
src/common/tests/Makefile.am
Normal file
76
src/common/tests/Makefile.am
Normal file
@ -0,0 +1,76 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
#
|
||||
# Unit tests for libguac_common
|
||||
#
|
||||
|
||||
check_PROGRAMS = test_common
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
noinst_HEADERS = \
|
||||
iconv/convert-test-data.h
|
||||
|
||||
test_common_SOURCES = \
|
||||
iconv/convert.c \
|
||||
iconv/convert-test-data.c \
|
||||
rect/clip_and_split.c \
|
||||
rect/constrain.c \
|
||||
rect/expand_to_grid.c \
|
||||
rect/extend.c \
|
||||
rect/init.c \
|
||||
rect/intersects.c \
|
||||
string/count_occurrences.c \
|
||||
string/split.c
|
||||
|
||||
test_common_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@COMMON_INCLUDE@
|
||||
|
||||
test_common_LDADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@CUNIT_LIBS@
|
||||
|
||||
#
|
||||
# Autogenerate test runner
|
||||
#
|
||||
|
||||
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_common_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_common_SOURCES) > $@
|
||||
|
||||
nodist_test_common_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
||||
# Use automake's TAP test driver for running any tests
|
||||
LOG_DRIVER = \
|
||||
env AM_TAP_AWK='$(AWK)' \
|
||||
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
|
||||
|
153
src/common/tests/iconv/convert-test-data.c
Normal file
153
src/common/tests/iconv/convert-test-data.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/iconv.h"
|
||||
#include "convert-test-data.h"
|
||||
|
||||
encoding_test_parameters test_params[NUM_SUPPORTED_ENCODINGS] = {
|
||||
|
||||
/*
|
||||
* UTF-8
|
||||
*/
|
||||
|
||||
{
|
||||
"UTF-8",
|
||||
GUAC_READ_UTF8, GUAC_READ_UTF8_NORMALIZED,
|
||||
GUAC_WRITE_UTF8, GUAC_WRITE_UTF8_CRLF,
|
||||
.test_mixed = TEST_STRING(
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello"
|
||||
),
|
||||
.test_unix = TEST_STRING(
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello"
|
||||
),
|
||||
.test_windows = TEST_STRING(
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
|
||||
"pap\xC3\xA0 \xC3\xA8 bello"
|
||||
)
|
||||
},
|
||||
|
||||
/*
|
||||
* UTF-16
|
||||
*/
|
||||
|
||||
{
|
||||
"UTF-16",
|
||||
GUAC_READ_UTF16, GUAC_READ_UTF16_NORMALIZED,
|
||||
GUAC_WRITE_UTF16, GUAC_WRITE_UTF16_CRLF,
|
||||
.test_mixed = TEST_STRING(
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
|
||||
"\x00"
|
||||
),
|
||||
.test_unix = TEST_STRING(
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
|
||||
"\x00"
|
||||
),
|
||||
.test_windows = TEST_STRING(
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
|
||||
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
|
||||
"\x00"
|
||||
)
|
||||
},
|
||||
|
||||
/*
|
||||
* ISO 8859-1
|
||||
*/
|
||||
|
||||
{
|
||||
"ISO 8859-1",
|
||||
GUAC_READ_ISO8859_1, GUAC_READ_ISO8859_1_NORMALIZED,
|
||||
GUAC_WRITE_ISO8859_1, GUAC_WRITE_ISO8859_1_CRLF,
|
||||
.test_mixed = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
),
|
||||
.test_unix = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
),
|
||||
.test_windows = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
)
|
||||
},
|
||||
|
||||
/*
|
||||
* CP-1252
|
||||
*/
|
||||
|
||||
{
|
||||
"CP-1252",
|
||||
GUAC_READ_CP1252, GUAC_READ_CP1252_NORMALIZED,
|
||||
GUAC_WRITE_CP1252, GUAC_WRITE_CP1252_CRLF,
|
||||
.test_mixed = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
),
|
||||
.test_unix = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
),
|
||||
.test_windows = TEST_STRING(
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello\r\n"
|
||||
"pap\xE0 \xE8 bello"
|
||||
)
|
||||
}
|
||||
|
||||
};
|
||||
|
121
src/common/tests/iconv/convert-test-data.h
Normal file
121
src/common/tests/iconv/convert-test-data.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/iconv.h"
|
||||
|
||||
/**
|
||||
* Representation of test string data and its length in bytes.
|
||||
*/
|
||||
typedef struct test_string {
|
||||
|
||||
/**
|
||||
* The raw content of the test string.
|
||||
*/
|
||||
unsigned char* buffer;
|
||||
|
||||
/**
|
||||
* The number of bytes within the test string, including null terminator.
|
||||
*/
|
||||
int size;
|
||||
|
||||
} test_string;
|
||||
|
||||
/**
|
||||
* Convenience macro which statically-initializes a test_string with the given
|
||||
* string value, automatically calculating its size in bytes.
|
||||
*
|
||||
* @param value
|
||||
* The string value.
|
||||
*/
|
||||
#define TEST_STRING(value) { \
|
||||
.buffer = (unsigned char*) (value), \
|
||||
.size = sizeof(value) \
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters applicable to a unit test for a particular encoding supported
|
||||
* by guac_iconv().
|
||||
*/
|
||||
typedef struct encoding_test_parameters {
|
||||
|
||||
/**
|
||||
* The human-readable name of this encoding. This will be logged to the
|
||||
* test suite log to assist with debugging test failures.
|
||||
*/
|
||||
const char* name;
|
||||
|
||||
/**
|
||||
* Reader function which reads using this encoding and does not perform any
|
||||
* transformation on newline characters.
|
||||
*/
|
||||
guac_iconv_read* reader;
|
||||
|
||||
/**
|
||||
* Reader function which reads using this encoding and automatically
|
||||
* normalizes newline sequences to Unix-style newline characters.
|
||||
*/
|
||||
guac_iconv_read* reader_normalized;
|
||||
|
||||
/**
|
||||
* Writer function which writes using this encoding and does not perform
|
||||
* any transformation on newline characters.
|
||||
*/
|
||||
guac_iconv_write* writer;
|
||||
|
||||
/**
|
||||
* Writer function which writes using this encoding, but writes newline
|
||||
* characters as CRLF sequences.
|
||||
*/
|
||||
guac_iconv_write* writer_crlf;
|
||||
|
||||
/**
|
||||
* A test string having both Windows- and Unix-style line endings. Except
|
||||
* for the line endings, the characters represented within this test string
|
||||
* must be identical to all other test strings.
|
||||
*/
|
||||
test_string test_mixed;
|
||||
|
||||
/**
|
||||
* A test string having only Unix-style line endings. Except for the line
|
||||
* endings, the characters represented within this test string must be
|
||||
* identical to all other test strings.
|
||||
*/
|
||||
test_string test_unix;
|
||||
|
||||
/**
|
||||
* A test string having only Windows-style line endings. Except for the
|
||||
* line endings, the characters represented within this test string must be
|
||||
* identical to all other test strings.
|
||||
*/
|
||||
test_string test_windows;
|
||||
|
||||
} encoding_test_parameters;
|
||||
|
||||
/**
|
||||
* The total number of encodings supported by guac_iconv().
|
||||
*/
|
||||
#define NUM_SUPPORTED_ENCODINGS 4
|
||||
|
||||
/**
|
||||
* Test parameters for each supported encoding. The test strings included each
|
||||
* consist of five repeated lines of "papà è bello", omitting the line ending
|
||||
* of the final line.
|
||||
*/
|
||||
extern encoding_test_parameters test_params[NUM_SUPPORTED_ENCODINGS];
|
||||
|
129
src/common/tests/iconv/convert.c
Normal file
129
src/common/tests/iconv/convert.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/iconv.h"
|
||||
#include "convert-test-data.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* Tests that conversion between character sets using the given guac_iconv_read
|
||||
* and guac_iconv_write implementations matches expectations.
|
||||
*
|
||||
* @param reader
|
||||
* The guac_iconv_read implementation to use to read the input string.
|
||||
*
|
||||
* @param in_string
|
||||
* A pointer to the test_string structure describing the input string being
|
||||
* tested.
|
||||
*
|
||||
* @param writer
|
||||
* The guac_iconv_write implementation to use to write the output string
|
||||
* (the converted input string).
|
||||
*
|
||||
* @param out_string
|
||||
* A pointer to the test_string structure describing the expected result of
|
||||
* the conversion.
|
||||
*/
|
||||
static void verify_conversion(
|
||||
guac_iconv_read* reader, test_string* in_string,
|
||||
guac_iconv_write* writer, test_string* out_string) {
|
||||
|
||||
char output[4096];
|
||||
char input[4096];
|
||||
|
||||
const char* current_input = input;
|
||||
char* current_output = output;
|
||||
|
||||
memcpy(input, in_string->buffer, in_string->size);
|
||||
guac_iconv(reader, ¤t_input, sizeof(input),
|
||||
writer, ¤t_output, sizeof(output));
|
||||
|
||||
/* Verify output length */
|
||||
CU_ASSERT_EQUAL(out_string->size, current_output - output);
|
||||
|
||||
/* Verify entire input read */
|
||||
CU_ASSERT_EQUAL(in_string->size, current_input - input);
|
||||
|
||||
/* Verify output content */
|
||||
CU_ASSERT_EQUAL(0, memcmp(output, out_string->buffer, out_string->size));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that every supported encoding can be correctly converted
|
||||
* to every other supported encoding, with all line endings preserved verbatim
|
||||
* (not normalized).
|
||||
*/
|
||||
void test_iconv__preserve() {
|
||||
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
|
||||
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
|
||||
|
||||
encoding_test_parameters* from = &test_params[i];
|
||||
encoding_test_parameters* to = &test_params[j];
|
||||
|
||||
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
|
||||
verify_conversion(from->reader, &from->test_mixed,
|
||||
to->writer, &to->test_mixed);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that every supported encoding can be correctly converted
|
||||
* to every other supported encoding, normalizing all line endings to
|
||||
* Unix-style line endings.
|
||||
*/
|
||||
void test_iconv__normalize_unix() {
|
||||
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
|
||||
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
|
||||
|
||||
encoding_test_parameters* from = &test_params[i];
|
||||
encoding_test_parameters* to = &test_params[j];
|
||||
|
||||
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
|
||||
verify_conversion(from->reader_normalized, &from->test_mixed,
|
||||
to->writer, &to->test_unix);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that every supported encoding can be correctly converted
|
||||
* to every other supported encoding, normalizing all line endings to
|
||||
* Windows-style line endings.
|
||||
*/
|
||||
void test_iconv__normalize_crlf() {
|
||||
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
|
||||
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
|
||||
|
||||
encoding_test_parameters* from = &test_params[i];
|
||||
encoding_test_parameters* to = &test_params[j];
|
||||
|
||||
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
|
||||
verify_conversion(from->reader_normalized, &from->test_mixed,
|
||||
to->writer_crlf, &to->test_windows);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
src/common/tests/rect/clip_and_split.c
Normal file
156
src/common/tests/rect/clip_and_split.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that guac_common_rect_clip_and_split() divides a
|
||||
* rectangle into subrectangles after removing a "hole" rectangle.
|
||||
*/
|
||||
void test_rect__clip_and_split() {
|
||||
|
||||
int res;
|
||||
|
||||
guac_common_rect cut;
|
||||
guac_common_rect min;
|
||||
guac_common_rect rect;
|
||||
|
||||
guac_common_rect_init(&min, 10, 10, 10, 10);
|
||||
|
||||
/* Clip top */
|
||||
guac_common_rect_init(&rect, 10, 5, 10, 10);
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(10, cut.x);
|
||||
CU_ASSERT_EQUAL(5, cut.y);
|
||||
CU_ASSERT_EQUAL(10, cut.width);
|
||||
CU_ASSERT_EQUAL(5, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(10, rect.width);
|
||||
CU_ASSERT_EQUAL(5, rect.height);
|
||||
|
||||
/* Clip bottom */
|
||||
guac_common_rect_init(&rect, 10, 15, 10, 10);
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(10, cut.x);
|
||||
CU_ASSERT_EQUAL(20, cut.y);
|
||||
CU_ASSERT_EQUAL(10, cut.width);
|
||||
CU_ASSERT_EQUAL(5, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(15, rect.y);
|
||||
CU_ASSERT_EQUAL(10, rect.width);
|
||||
CU_ASSERT_EQUAL(5, rect.height);
|
||||
|
||||
/* Clip left */
|
||||
guac_common_rect_init(&rect, 5, 10, 10, 10);
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(5, cut.x);
|
||||
CU_ASSERT_EQUAL(10, cut.y);
|
||||
CU_ASSERT_EQUAL(5, cut.width);
|
||||
CU_ASSERT_EQUAL(10, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(5, rect.width);
|
||||
CU_ASSERT_EQUAL(10, rect.height);
|
||||
|
||||
/* Clip right */
|
||||
guac_common_rect_init(&rect, 15, 10, 10, 10);
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(20, cut.x);
|
||||
CU_ASSERT_EQUAL(10, cut.y);
|
||||
CU_ASSERT_EQUAL(5, cut.width);
|
||||
CU_ASSERT_EQUAL(10, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(15, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(5, rect.width);
|
||||
CU_ASSERT_EQUAL(10, rect.height);
|
||||
|
||||
/*
|
||||
* Test a rectangle which completely covers the hole.
|
||||
* Clip and split until done.
|
||||
*/
|
||||
guac_common_rect_init(&rect, 5, 5, 20, 20);
|
||||
|
||||
/* Clip top */
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(5, cut.x);
|
||||
CU_ASSERT_EQUAL(5, cut.y);
|
||||
CU_ASSERT_EQUAL(20, cut.width);
|
||||
CU_ASSERT_EQUAL(5, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(5, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(20, rect.width);
|
||||
CU_ASSERT_EQUAL(15, rect.height);
|
||||
|
||||
/* Clip left */
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(5, cut.x);
|
||||
CU_ASSERT_EQUAL(10, cut.y);
|
||||
CU_ASSERT_EQUAL(5, cut.width);
|
||||
CU_ASSERT_EQUAL(15, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(15, rect.width);
|
||||
CU_ASSERT_EQUAL(15, rect.height);
|
||||
|
||||
/* Clip bottom */
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
CU_ASSERT_EQUAL(10, cut.x);
|
||||
CU_ASSERT_EQUAL(20, cut.y);
|
||||
CU_ASSERT_EQUAL(15, cut.width);
|
||||
CU_ASSERT_EQUAL(5, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(15, rect.width);
|
||||
CU_ASSERT_EQUAL(10, rect.height);
|
||||
|
||||
/* Clip right */
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(20, cut.x);
|
||||
CU_ASSERT_EQUAL(10, cut.y);
|
||||
CU_ASSERT_EQUAL(5, cut.width);
|
||||
CU_ASSERT_EQUAL(10, cut.height);
|
||||
|
||||
CU_ASSERT_EQUAL(10, rect.x);
|
||||
CU_ASSERT_EQUAL(10, rect.y);
|
||||
CU_ASSERT_EQUAL(10, rect.width);
|
||||
CU_ASSERT_EQUAL(10, rect.height);
|
||||
|
||||
/* Make sure nothing is left to do */
|
||||
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
|
||||
CU_ASSERT_EQUAL(0, res);
|
||||
|
||||
}
|
||||
|
43
src/common/tests/rect/constrain.c
Normal file
43
src/common/tests/rect/constrain.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that guac_common_rect_constrain() restricts a given
|
||||
* rectangle to arbitrary bounds.
|
||||
*/
|
||||
void test_rect__constrain() {
|
||||
|
||||
guac_common_rect max;
|
||||
guac_common_rect rect;
|
||||
|
||||
guac_common_rect_init(&rect, -10, -10, 110, 110);
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
guac_common_rect_constrain(&rect, &max);
|
||||
|
||||
CU_ASSERT_EQUAL(0, rect.x);
|
||||
CU_ASSERT_EQUAL(0, rect.y);
|
||||
CU_ASSERT_EQUAL(100, rect.width);
|
||||
CU_ASSERT_EQUAL(100, rect.height);
|
||||
|
||||
}
|
||||
|
71
src/common/tests/rect/expand_to_grid.c
Normal file
71
src/common/tests/rect/expand_to_grid.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies guac_common_rect_expand_to_grid() properly shifts and
|
||||
* resizes rectangles to fit an NxN grid.
|
||||
*/
|
||||
void test_rect__expand_to_grid() {
|
||||
|
||||
int cell_size = 16;
|
||||
|
||||
guac_common_rect max;
|
||||
guac_common_rect rect;
|
||||
|
||||
/* Simple adjustment */
|
||||
guac_common_rect_init(&rect, 0, 0, 25, 25);
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
|
||||
CU_ASSERT_EQUAL(0, rect.x);
|
||||
CU_ASSERT_EQUAL(0, rect.y);
|
||||
CU_ASSERT_EQUAL(32, rect.width);
|
||||
CU_ASSERT_EQUAL(32, rect.height);
|
||||
|
||||
/* Adjustment with moving of rect */
|
||||
guac_common_rect_init(&rect, 75, 75, 25, 25);
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
|
||||
CU_ASSERT_EQUAL(max.width - 32, rect.x);
|
||||
CU_ASSERT_EQUAL(max.height - 32, rect.y);
|
||||
CU_ASSERT_EQUAL(32, rect.width);
|
||||
CU_ASSERT_EQUAL(32, rect.height);
|
||||
|
||||
guac_common_rect_init(&rect, -5, -5, 25, 25);
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
|
||||
CU_ASSERT_EQUAL(0, rect.x);
|
||||
CU_ASSERT_EQUAL(0, rect.y);
|
||||
CU_ASSERT_EQUAL(32, rect.width);
|
||||
CU_ASSERT_EQUAL(32, rect.height);
|
||||
|
||||
/* Adjustment with moving and clamping of rect */
|
||||
guac_common_rect_init(&rect, 0, 0, 25, 15);
|
||||
guac_common_rect_init(&max, 0, 5, 32, 15);
|
||||
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
|
||||
CU_ASSERT_EQUAL(max.x, rect.x);
|
||||
CU_ASSERT_EQUAL(max.y, rect.y);
|
||||
CU_ASSERT_EQUAL(max.width, rect.width);
|
||||
CU_ASSERT_EQUAL(max.height, rect.height);
|
||||
|
||||
}
|
||||
|
42
src/common/tests/rect/extend.c
Normal file
42
src/common/tests/rect/extend.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that guac_common_rect_extend() expands the given
|
||||
* rectangle as necessary to contain at least the given bounds.
|
||||
*/
|
||||
void test_rect__extend() {
|
||||
|
||||
guac_common_rect max;
|
||||
guac_common_rect rect;
|
||||
|
||||
guac_common_rect_init(&rect, 10, 10, 90, 90);
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
guac_common_rect_extend(&rect, &max);
|
||||
CU_ASSERT_EQUAL(0, rect.x);
|
||||
CU_ASSERT_EQUAL(0, rect.y);
|
||||
CU_ASSERT_EQUAL(100, rect.width);
|
||||
CU_ASSERT_EQUAL(100, rect.height);
|
||||
|
||||
}
|
||||
|
39
src/common/tests/rect/init.c
Normal file
39
src/common/tests/rect/init.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies rectangle initialization via guac_common_rect_init().
|
||||
*/
|
||||
void test_rect__init() {
|
||||
|
||||
guac_common_rect max;
|
||||
|
||||
guac_common_rect_init(&max, 0, 0, 100, 100);
|
||||
|
||||
CU_ASSERT_EQUAL(0, max.x);
|
||||
CU_ASSERT_EQUAL(0, max.y);
|
||||
CU_ASSERT_EQUAL(100, max.width);
|
||||
CU_ASSERT_EQUAL(100, max.height);
|
||||
|
||||
}
|
||||
|
91
src/common/tests/rect/intersects.c
Normal file
91
src/common/tests/rect/intersects.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies intersection testing via guac_common_rect_intersects().
|
||||
*/
|
||||
void test_rect__intersects() {
|
||||
|
||||
int res;
|
||||
|
||||
guac_common_rect min;
|
||||
guac_common_rect rect;
|
||||
|
||||
guac_common_rect_init(&min, 10, 10, 10, 10);
|
||||
|
||||
/* Rectangle intersection - empty
|
||||
* rectangle is outside */
|
||||
guac_common_rect_init(&rect, 25, 25, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(0, res);
|
||||
|
||||
/* Rectangle intersection - complete
|
||||
* rectangle is completely inside */
|
||||
guac_common_rect_init(&rect, 11, 11, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(2, res);
|
||||
|
||||
/* Rectangle intersection - partial
|
||||
* rectangle intersects UL */
|
||||
guac_common_rect_init(&rect, 8, 8, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
|
||||
/* Rectangle intersection - partial
|
||||
* rectangle intersects LR */
|
||||
guac_common_rect_init(&rect, 18, 18, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
|
||||
/* Rectangle intersection - complete
|
||||
* rect intersects along UL but inside */
|
||||
guac_common_rect_init(&rect, 10, 10, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(2, res);
|
||||
|
||||
/* Rectangle intersection - partial
|
||||
* rectangle intersects along L but outside */
|
||||
guac_common_rect_init(&rect, 5, 10, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
|
||||
/* Rectangle intersection - complete
|
||||
* rectangle intersects along LR but rest is inside */
|
||||
guac_common_rect_init(&rect, 15, 15, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(2, res);
|
||||
|
||||
/* Rectangle intersection - partial
|
||||
* rectangle intersects along R but rest is outside */
|
||||
guac_common_rect_init(&rect, 20, 10, 5, 5);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
|
||||
/* Rectangle intersection - partial
|
||||
* rectangle encloses min; which is a partial intersection */
|
||||
guac_common_rect_init(&rect, 5, 5, 20, 20);
|
||||
res = guac_common_rect_intersects(&rect, &min);
|
||||
CU_ASSERT_EQUAL(1, res);
|
||||
|
||||
}
|
||||
|
33
src/common/tests/string/count_occurrences.c
Normal file
33
src/common/tests/string/count_occurrences.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/string.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that guac_count_occurrences() counts the number of
|
||||
* occurrences of an arbitrary character within a given string.
|
||||
*/
|
||||
void test_string__guac_count_occurrences() {
|
||||
CU_ASSERT_EQUAL(4, guac_count_occurrences("this is a test string", 's'));
|
||||
CU_ASSERT_EQUAL(3, guac_count_occurrences("this is a test string", 'i'));
|
||||
CU_ASSERT_EQUAL(0, guac_count_occurrences("", 's'));
|
||||
}
|
||||
|
63
src/common/tests/string/split.c
Normal file
63
src/common/tests/string/split.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "common/string.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Test which verifies that guac_split() splits a string on occurrences of a
|
||||
* given character.
|
||||
*/
|
||||
void test_string__split() {
|
||||
|
||||
/* Split test string */
|
||||
char** tokens = guac_split("this is a test string", ' ');
|
||||
CU_ASSERT_PTR_NOT_NULL(tokens);
|
||||
|
||||
/* Check resulting tokens */
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[0]);
|
||||
CU_ASSERT_STRING_EQUAL("this", tokens[0]);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[1]);
|
||||
CU_ASSERT_STRING_EQUAL("is", tokens[1]);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[2]);
|
||||
CU_ASSERT_STRING_EQUAL("a", tokens[2]);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[3]);
|
||||
CU_ASSERT_STRING_EQUAL("test", tokens[3]);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(tokens[4]);
|
||||
CU_ASSERT_STRING_EQUAL("string", tokens[4]);
|
||||
|
||||
CU_ASSERT_PTR_NULL(tokens[5]);
|
||||
|
||||
/* Clean up */
|
||||
free(tokens[0]);
|
||||
free(tokens[1]);
|
||||
free(tokens[2]);
|
||||
free(tokens[3]);
|
||||
free(tokens[4]);
|
||||
free(tokens);
|
||||
|
||||
}
|
||||
|
46
src/guacd-docker/README.md
Normal file
46
src/guacd-docker/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
What is guacd?
|
||||
==============
|
||||
|
||||
[guacd](https://github.com/apache/guacamole-server/) is the native
|
||||
server-side proxy used by the [Apache Guacamole web
|
||||
application](http://guacamole.apache.org/). If you wish to deploy
|
||||
Guacamole, or an application using the [Guacamole core
|
||||
APIs](http://guacamole.apache.org/api-documentation), you will need a
|
||||
copy of guacd running.
|
||||
|
||||
How to use this image
|
||||
=====================
|
||||
|
||||
Running guacd for use by the [Guacamole Docker image](https://registry.hub.docker.com/u/guacamole/guacamole/)
|
||||
-----------------------------------------------------
|
||||
|
||||
docker run --name some-guacd -d guacamole/guacd
|
||||
|
||||
guacd will be listening on port 4822, but this port will only be available to
|
||||
Docker containers that have been explicitly linked to `some-guacd`.
|
||||
|
||||
Running guacd for use services by outside Docker
|
||||
------------------------------------------------
|
||||
|
||||
docker run --name some-guacd -d -p 4822:4822 guacamole/guacd
|
||||
|
||||
guacd will be listening on port 4822, and Docker will expose this port on the
|
||||
same server hosting Docker. Other services, such as an instance of Tomcat
|
||||
running outside of Docker, will be able to connect to guacd.
|
||||
|
||||
Beware of the security ramifications of doing this. There is no authentication
|
||||
within guacd, so allowing access from untrusted applications is dangerous. If
|
||||
you need to expose guacd, ensure that you only expose it as absolutely
|
||||
necessary, and that only specific trusted applications have access.
|
||||
|
||||
Connecting to guacd from an application
|
||||
---------------------------------------
|
||||
|
||||
docker run --name some-app --link some-guacd:guacd -d application-that-uses-guacd
|
||||
|
||||
Reporting issues
|
||||
================
|
||||
|
||||
Please report any bugs encountered by opening a new issue in
|
||||
[our JIRA](https://issues.apache.org/jira/browse/GUACAMOLE/).
|
||||
|
115
src/guacd-docker/bin/build-all.sh
Executable file
115
src/guacd-docker/bin/build-all.sh
Executable file
@ -0,0 +1,115 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
##
|
||||
## @fn build-all.sh
|
||||
##
|
||||
## Builds the source of guacamole-server and its various core protocol library
|
||||
## dependencies.
|
||||
##
|
||||
|
||||
# Pre-populate build control variables such that the custom build prefix is
|
||||
# used for C headers, locating libraries, etc.
|
||||
export CFLAGS="-I${PREFIX_DIR}/include"
|
||||
export LDFLAGS="-L${PREFIX_DIR}/lib"
|
||||
export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig"
|
||||
|
||||
# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
|
||||
# 128 KB (musl's default)
|
||||
export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
|
||||
|
||||
##
|
||||
## Builds and installs the source at the given git repository, automatically
|
||||
## switching to the version of the source at the tag/commit that matches the
|
||||
## given pattern.
|
||||
##
|
||||
## @param URL
|
||||
## The URL of the git repository that the source should be downloaded from.
|
||||
##
|
||||
## @param PATTERN
|
||||
## The Perl-compatible regular expression that the tag must match. If no
|
||||
## tag matches the regular expression, the pattern is assumed to be an
|
||||
## exact reference to a commit, branch, etc. acceptable by git checkout.
|
||||
##
|
||||
## @param ...
|
||||
## Any additional command-line options that should be provided to CMake or
|
||||
## the configure script.
|
||||
##
|
||||
install_from_git() {
|
||||
|
||||
URL="$1"
|
||||
PATTERN="$2"
|
||||
shift 2
|
||||
|
||||
# Calculate top-level directory name of resulting repository from the
|
||||
# provided URL
|
||||
REPO_DIR="$(basename "$URL" .git)"
|
||||
|
||||
# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
|
||||
if [ "$PATTERN" = "NO" ]; then
|
||||
echo "NOT building $REPO_DIR (explicitly skipped)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Clone repository and change to top-level directory of source
|
||||
cd /tmp
|
||||
git clone "$URL"
|
||||
cd $REPO_DIR/
|
||||
|
||||
# Locate tag/commit based on provided pattern
|
||||
VERSION="$(git tag -l --sort=-v:refname | grep -Px -m1 "$PATTERN" \
|
||||
|| echo "$PATTERN")"
|
||||
|
||||
# Switch to desired version of source
|
||||
echo "Building $REPO_DIR @ $VERSION ..."
|
||||
git -c advice.detachedHead=false checkout "$VERSION"
|
||||
|
||||
# Configure build using CMake or GNU Autotools, whichever happens to be
|
||||
# used by the library being built
|
||||
if [ -e CMakeLists.txt ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX_DIR" "$@" .
|
||||
else
|
||||
[ -e configure ] || autoreconf -fi
|
||||
./configure --prefix="$PREFIX_DIR" "$@"
|
||||
fi
|
||||
|
||||
# Build and install
|
||||
make && make install
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# Build and install core protocol library dependencies
|
||||
#
|
||||
|
||||
install_from_git "https://github.com/FreeRDP/FreeRDP" "$WITH_FREERDP" $FREERDP_OPTS
|
||||
install_from_git "https://github.com/libssh2/libssh2" "$WITH_LIBSSH2" $LIBSSH2_OPTS
|
||||
install_from_git "https://github.com/seanmiddleditch/libtelnet" "$WITH_LIBTELNET" $LIBTELNET_OPTS
|
||||
install_from_git "https://github.com/LibVNC/libvncserver" "$WITH_LIBVNCCLIENT" $LIBVNCCLIENT_OPTS
|
||||
install_from_git "https://libwebsockets.org/repo/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS
|
||||
|
||||
#
|
||||
# Build guacamole-server
|
||||
#
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
autoreconf -fi && ./configure --prefix="$PREFIX_DIR" $GUACAMOLE_SERVER_OPTS
|
||||
make && make install
|
||||
|
51
src/guacd-docker/bin/list-dependencies.sh
Executable file
51
src/guacd-docker/bin/list-dependencies.sh
Executable file
@ -0,0 +1,51 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
##
|
||||
## @fn list-dependencies.sh
|
||||
##
|
||||
## Lists the Alpine Linux package names for all library dependencies of the
|
||||
## given binaries. Each package is only listed once, even if multiple binaries
|
||||
## provided by the same package are given.
|
||||
##
|
||||
## @param ...
|
||||
## The full paths to all binaries being checked.
|
||||
##
|
||||
|
||||
while [ -n "$1" ]; do
|
||||
|
||||
# For all non-Guacamole library dependencies
|
||||
ldd "$1" | grep -v 'libguac' | awk '/=>/{print $(NF-1)}' \
|
||||
| while read LIBRARY; do
|
||||
|
||||
# List the package providing that library, if any
|
||||
apk info -W "$LIBRARY" 2> /dev/null \
|
||||
| grep 'is owned by' | grep -o '[^ ]*$' || true
|
||||
|
||||
done
|
||||
|
||||
# Next binary
|
||||
shift
|
||||
|
||||
# Strip the "-VERSION" suffix from each package name, listing each resulting
|
||||
# package uniquely ("apk add" cannot handle package names that include the
|
||||
# version number)
|
||||
done | sed 's/\(.*\)-[0-9]\+\..*$/\1/' | sort -u
|
||||
|
40
src/guacd/.gitignore
vendored
40
src/guacd/.gitignore
vendored
@ -2,42 +2,14 @@
|
||||
# Compiled init script
|
||||
init.d/guacd
|
||||
|
||||
# Compiled systemd unit
|
||||
systemd/guacd.service
|
||||
|
||||
# Compiled proxy
|
||||
guacd
|
||||
guacd.exe
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.lo
|
||||
*.la
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
# Release files
|
||||
*.tar.gz
|
||||
|
||||
# Files currently being edited by vim or vi
|
||||
*.swp
|
||||
|
||||
# automake/autoconf
|
||||
.deps/
|
||||
.libs/
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
m4/
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
|
||||
# Documentation (built from .in files)
|
||||
man/guacd.8
|
||||
man/guacd.conf.5
|
||||
|
||||
|
@ -1,45 +1,78 @@
|
||||
#
|
||||
# Copyright (C) 2013 Glyptodon LLC
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@ @COMMON_INCLUDE@
|
||||
|
||||
sbin_PROGRAMS = guacd
|
||||
man_MANS = man/guacd.8
|
||||
|
||||
noinst_HEADERS = client.h client-map.h log.h
|
||||
guacd_SOURCES = daemon.c client.c client-map.c log.c
|
||||
guacd_LDADD = @LIBGUAC_LTLIB@ @COMMON_LTLIB@
|
||||
guacd_LDFLAGS = @PTHREAD_LIBS@ @SSL_LIBS@
|
||||
man_MANS = \
|
||||
man/guacd.8 \
|
||||
man/guacd.conf.5
|
||||
|
||||
EXTRA_DIST = init.d/guacd.in man/guacd.8
|
||||
CLEANFILES = $(init_SCRIPTS)
|
||||
noinst_HEADERS = \
|
||||
conf.h \
|
||||
conf-args.h \
|
||||
conf-file.h \
|
||||
conf-parse.h \
|
||||
connection.h \
|
||||
log.h \
|
||||
move-fd.h \
|
||||
proc.h \
|
||||
proc-map.h
|
||||
|
||||
# SSL support
|
||||
if ENABLE_SSL
|
||||
noinst_HEADERS += socket-ssl.h
|
||||
guacd_SOURCES += socket-ssl.c
|
||||
endif
|
||||
guacd_SOURCES = \
|
||||
conf-args.c \
|
||||
conf-file.c \
|
||||
conf-parse.c \
|
||||
connection.c \
|
||||
daemon.c \
|
||||
log.c \
|
||||
move-fd.c \
|
||||
proc.c \
|
||||
proc-map.c
|
||||
|
||||
guacd_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@COMMON_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@
|
||||
|
||||
guacd_LDADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
guacd_LDFLAGS = \
|
||||
@PTHREAD_LIBS@ \
|
||||
@SSL_LIBS@
|
||||
|
||||
EXTRA_DIST = \
|
||||
init.d/guacd.in \
|
||||
systemd/guacd.service.in \
|
||||
man/guacd.8.in \
|
||||
man/guacd.conf.5.in
|
||||
|
||||
CLEANFILES = $(init_SCRIPTS) $(systemd_UNITS)
|
||||
|
||||
# Init script
|
||||
if ENABLE_INIT
|
||||
@ -51,3 +84,12 @@ init.d/guacd: init.d/guacd.in
|
||||
chmod +x init.d/guacd
|
||||
endif
|
||||
|
||||
# Systemd service
|
||||
if ENABLE_SYSTEMD
|
||||
systemddir = @systemd_dir@
|
||||
systemd_DATA = systemd/guacd.service
|
||||
|
||||
systemd/guacd.service: systemd/guacd.service.in
|
||||
sed -e 's,[@]sbindir[@],$(sbindir),g' < systemd/guacd.service.in > systemd/guacd.service
|
||||
endif
|
||||
|
||||
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
#include "client-map.h"
|
||||
#include "guac_list.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Returns a hash code based on the connection ID of the given client.
|
||||
*/
|
||||
static unsigned int __guacd_client_hash(const char* str) {
|
||||
|
||||
unsigned int hash_value = 0;
|
||||
int c;
|
||||
|
||||
/* Apply each character in string to the hash code */
|
||||
while ((c = *(str++)))
|
||||
hash_value = hash_value * 65599 + c;
|
||||
|
||||
return hash_value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the bucket corresponding to the hash code indicated by the give id.
|
||||
* Each bucket is an instance of guac_common_list.
|
||||
*/
|
||||
static guac_common_list* __guacd_client_find_bucket(guacd_client_map* map, const char* id) {
|
||||
|
||||
const int index = __guacd_client_hash(id) % GUACD_CLIENT_MAP_BUCKETS;
|
||||
return map->__buckets[index];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of guac_client instances, returns the guac_client having the
|
||||
* given ID, or NULL if no such client is stored.
|
||||
*/
|
||||
static guac_common_list_element* __guacd_client_find(guac_common_list* bucket, const char* id) {
|
||||
|
||||
guac_common_list_element* current = bucket->head;
|
||||
|
||||
/* Search for matching element within bucket */
|
||||
while (current != NULL) {
|
||||
|
||||
/* Check connection ID */
|
||||
guac_client* client = (guac_client*) current->data;
|
||||
if (strcmp(client->connection_id, id) == 0)
|
||||
break;
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return current;
|
||||
|
||||
}
|
||||
|
||||
guacd_client_map* guacd_client_map_alloc() {
|
||||
|
||||
guacd_client_map* map = malloc(sizeof(guacd_client_map));
|
||||
guac_common_list** current;
|
||||
|
||||
int i;
|
||||
|
||||
/* Init all buckets */
|
||||
current = map->__buckets;
|
||||
|
||||
for (i=0; i<GUACD_CLIENT_MAP_BUCKETS; i++) {
|
||||
*current = guac_common_list_alloc();
|
||||
current++;
|
||||
}
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
int guacd_client_map_add(guacd_client_map* map, guac_client* client) {
|
||||
|
||||
guac_common_list* bucket = __guacd_client_find_bucket(map, client->connection_id);
|
||||
guac_common_list_element* found;
|
||||
|
||||
/* Retrieve corresponding element, if any */
|
||||
guac_common_list_lock(bucket);
|
||||
found = __guacd_client_find(bucket, client->connection_id);
|
||||
|
||||
/* If no such element, we can add the new client successfully */
|
||||
if (found == NULL) {
|
||||
guac_common_list_add(bucket, client);
|
||||
guac_common_list_unlock(bucket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, fail - already exists */
|
||||
guac_common_list_unlock(bucket);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
guac_client* guacd_client_map_retrieve(guacd_client_map* map, const char* id) {
|
||||
|
||||
guac_client* client;
|
||||
|
||||
guac_common_list* bucket = __guacd_client_find_bucket(map, id);
|
||||
guac_common_list_element* found;
|
||||
|
||||
/* Retrieve corresponding element, if any */
|
||||
guac_common_list_lock(bucket);
|
||||
found = __guacd_client_find(bucket, id);
|
||||
|
||||
/* If no such element, fail */
|
||||
if (found == NULL) {
|
||||
guac_common_list_unlock(bucket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
client = (guac_client*) found->data;
|
||||
|
||||
guac_common_list_unlock(bucket);
|
||||
return client;
|
||||
|
||||
}
|
||||
|
||||
guac_client* guacd_client_map_remove(guacd_client_map* map, const char* id) {
|
||||
|
||||
guac_client* client;
|
||||
|
||||
guac_common_list* bucket = __guacd_client_find_bucket(map, id);
|
||||
guac_common_list_element* found;
|
||||
|
||||
/* Retrieve corresponding element, if any */
|
||||
guac_common_list_lock(bucket);
|
||||
found = __guacd_client_find(bucket, id);
|
||||
|
||||
/* If no such element, fail */
|
||||
if (found == NULL) {
|
||||
guac_common_list_unlock(bucket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
client = (guac_client*) found->data;
|
||||
guac_common_list_remove(bucket, found);
|
||||
|
||||
guac_common_list_unlock(bucket);
|
||||
return client;
|
||||
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUACD_CLIENT_MAP_H
|
||||
#define _GUACD_CLIENT_MAP_H
|
||||
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
#include "guac_list.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#define GUACD_CLIENT_MAP_BUCKETS GUACD_CLIENT_MAX_CONNECTIONS*2
|
||||
|
||||
/**
|
||||
* Set of all active connections to guacd, indexed by connection ID.
|
||||
*/
|
||||
typedef struct guacd_client_map {
|
||||
|
||||
/**
|
||||
* Internal hash buckets. Each bucket is a linked list containing all
|
||||
* guac_client instances which hash to this bucket location.
|
||||
*/
|
||||
guac_common_list* __buckets[GUACD_CLIENT_MAP_BUCKETS];
|
||||
|
||||
} guacd_client_map;
|
||||
|
||||
/**
|
||||
* Allocates a new client map, which persists for the life of guacd.
|
||||
*/
|
||||
guacd_client_map* guacd_client_map_alloc();
|
||||
|
||||
/**
|
||||
* Adds the given client to the given client map. On success, zero is returned.
|
||||
* If adding the client fails (due to lack of space, or duplicate ID), a
|
||||
* non-zero value is returned instead.
|
||||
*/
|
||||
int guacd_client_map_add(guacd_client_map* map, guac_client* client);
|
||||
|
||||
/**
|
||||
* Retrieves the client having the given ID, or NULL if no such client
|
||||
* is stored.
|
||||
*/
|
||||
guac_client* guacd_client_map_retrieve(guacd_client_map* map, const char* id);
|
||||
|
||||
/**
|
||||
* Removes the client having the given ID, returning the corresponding client.
|
||||
* If no such client exists, NULL is returned.
|
||||
*/
|
||||
guac_client* guacd_client_map_remove(guacd_client_map* map, const char* id);
|
||||
|
||||
#endif
|
||||
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
#include <guacamole/instruction.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* Sleep for the given number of milliseconds.
|
||||
*
|
||||
* @param millis The number of milliseconds to sleep.
|
||||
*/
|
||||
void __guacdd_sleep(int millis) {
|
||||
|
||||
struct timespec sleep_period;
|
||||
|
||||
sleep_period.tv_sec = millis / 1000;
|
||||
sleep_period.tv_nsec = (millis % 1000) * 1000000L;
|
||||
|
||||
nanosleep(&sleep_period, NULL);
|
||||
|
||||
}
|
||||
|
||||
void* __guacd_client_output_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
guac_socket* socket = client->socket;
|
||||
|
||||
/* Guacamole client output loop */
|
||||
while (client->state == GUAC_CLIENT_RUNNING) {
|
||||
|
||||
/* Handle server messages */
|
||||
if (client->handle_messages) {
|
||||
|
||||
/* Only handle messages if synced within threshold */
|
||||
if (client->last_sent_timestamp - client->last_received_timestamp
|
||||
< GUACD_SYNC_THRESHOLD) {
|
||||
|
||||
int retval = client->handle_messages(client);
|
||||
if (retval) {
|
||||
guacd_client_log_guac_error(client,
|
||||
"Error handling server messages");
|
||||
guac_client_stop(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Send sync instruction */
|
||||
client->last_sent_timestamp = guac_timestamp_current();
|
||||
if (guac_protocol_send_sync(socket, client->last_sent_timestamp)) {
|
||||
guacd_client_log_guac_error(client,
|
||||
"Error sending \"sync\" instruction");
|
||||
guac_client_stop(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flush */
|
||||
if (guac_socket_flush(socket)) {
|
||||
guacd_client_log_guac_error(client,
|
||||
"Error flushing output");
|
||||
guac_client_stop(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Do not spin while waiting for old sync */
|
||||
else
|
||||
__guacdd_sleep(GUACD_MESSAGE_HANDLE_FREQUENCY);
|
||||
|
||||
}
|
||||
|
||||
/* If no message handler, just sleep until next sync ping */
|
||||
else
|
||||
__guacdd_sleep(GUACD_SYNC_FREQUENCY);
|
||||
|
||||
} /* End of output loop */
|
||||
|
||||
guac_client_stop(client);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void* __guacd_client_input_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
guac_socket* socket = client->socket;
|
||||
|
||||
/* Guacamole client input loop */
|
||||
while (client->state == GUAC_CLIENT_RUNNING) {
|
||||
|
||||
/* Read instruction */
|
||||
guac_instruction* instruction =
|
||||
guac_instruction_read(socket, GUACD_USEC_TIMEOUT);
|
||||
|
||||
/* Stop on error */
|
||||
if (instruction == NULL) {
|
||||
|
||||
if (guac_error == GUAC_STATUS_INPUT_TIMEOUT)
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "Client is not responding.");
|
||||
|
||||
else {
|
||||
guacd_client_log_guac_error(client, "Error reading instruction");
|
||||
guac_client_stop(client);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reset guac_error and guac_error_message (client handlers are not
|
||||
* guaranteed to set these) */
|
||||
guac_error = GUAC_STATUS_SUCCESS;
|
||||
guac_error_message = NULL;
|
||||
|
||||
/* Call handler, stop on error */
|
||||
if (guac_client_handle_instruction(client, instruction) < 0) {
|
||||
|
||||
/* Log error */
|
||||
guacd_client_log_guac_error(client,
|
||||
"Client instruction handler error");
|
||||
|
||||
/* Log handler details */
|
||||
guac_client_log_info(client,
|
||||
"Failing instruction handler in client was \"%s\"",
|
||||
instruction->opcode);
|
||||
|
||||
guac_instruction_free(instruction);
|
||||
guac_client_stop(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free allocated instruction */
|
||||
guac_instruction_free(instruction);
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int guacd_client_start(guac_client* client) {
|
||||
|
||||
pthread_t input_thread, output_thread;
|
||||
|
||||
if (pthread_create(&output_thread, NULL, __guacd_client_output_thread, (void*) client)) {
|
||||
guac_client_log_error(client, "Unable to start output thread");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pthread_create(&input_thread, NULL, __guacd_client_input_thread, (void*) client)) {
|
||||
guac_client_log_error(client, "Unable to start input thread");
|
||||
guac_client_stop(client);
|
||||
pthread_join(output_thread, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait for I/O threads */
|
||||
pthread_join(input_thread, NULL);
|
||||
pthread_join(output_thread, NULL);
|
||||
|
||||
/* Done */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GUACD_CLIENT_H
|
||||
#define _GUACD_CLIENT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* The time to allow between sync responses in milliseconds. If a sync
|
||||
* instruction is sent to the client and no response is received within this
|
||||
* timeframe, server messages will not be handled until a sync instruction is
|
||||
* received from the client.
|
||||
*/
|
||||
#define GUACD_SYNC_THRESHOLD 500
|
||||
|
||||
/**
|
||||
* The time to allow between server sync messages in milliseconds. A sync
|
||||
* message from the server will be sent every GUACD_SYNC_FREQUENCY milliseconds.
|
||||
* As this will induce a response from a client that is not malfunctioning,
|
||||
* this is used to detect when a client has died. This must be set to a
|
||||
* reasonable value to avoid clients being disconnected unnecessarily due
|
||||
* to timeout.
|
||||
*/
|
||||
#define GUACD_SYNC_FREQUENCY 5000
|
||||
|
||||
/**
|
||||
* The amount of time to wait after handling server messages. If a client
|
||||
* plugin has a message handler, and sends instructions when server messages
|
||||
* are being handled, there will be a pause of this many milliseconds before
|
||||
* the next call to the message handler.
|
||||
*/
|
||||
#define GUACD_MESSAGE_HANDLE_FREQUENCY 50
|
||||
|
||||
/**
|
||||
* The number of milliseconds to wait for messages in any phase before
|
||||
* timing out and closing the connection with an error.
|
||||
*/
|
||||
#define GUACD_TIMEOUT 15000
|
||||
|
||||
/**
|
||||
* The number of microseconds to wait for messages in any phase before
|
||||
* timing out and closing the conncetion with an error. This is always
|
||||
* equal to GUACD_TIMEOUT * 1000.
|
||||
*/
|
||||
#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
|
||||
|
||||
/**
|
||||
* The maximum number of concurrent connections to a single instance
|
||||
* of guacd.
|
||||
*/
|
||||
#define GUACD_CLIENT_MAX_CONNECTIONS 65536
|
||||
|
||||
int guacd_client_start(guac_client* client);
|
||||
|
||||
#endif
|
||||
|
124
src/guacd/conf-args.c
Normal file
124
src/guacd/conf-args.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "conf-args.h"
|
||||
#include "conf-parse.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) {
|
||||
|
||||
/* Parse arguments */
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "l:b:p:L:C:K:fv")) != -1) {
|
||||
|
||||
/* -l: Bind port */
|
||||
if (opt == 'l') {
|
||||
free(config->bind_port);
|
||||
config->bind_port = strdup(optarg);
|
||||
}
|
||||
|
||||
/* -b: Bind host */
|
||||
else if (opt == 'b') {
|
||||
free(config->bind_host);
|
||||
config->bind_host = strdup(optarg);
|
||||
}
|
||||
|
||||
/* -f: Run in foreground */
|
||||
else if (opt == 'f') {
|
||||
config->foreground = 1;
|
||||
}
|
||||
|
||||
/* -v: Print version and exit */
|
||||
else if (opt == 'v') {
|
||||
config->print_version = 1;
|
||||
}
|
||||
|
||||
/* -p: PID file */
|
||||
else if (opt == 'p') {
|
||||
free(config->pidfile);
|
||||
config->pidfile = strdup(optarg);
|
||||
}
|
||||
|
||||
/* -L: Log level */
|
||||
else if (opt == 'L') {
|
||||
|
||||
/* Validate and parse log level */
|
||||
int level = guacd_parse_log_level(optarg);
|
||||
if (level == -1) {
|
||||
fprintf(stderr, "Invalid log level. Valid levels are: \"trace\", \"debug\", \"info\", \"warning\", and \"error\".\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
config->max_log_level = level;
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SSL
|
||||
/* -C SSL certificate */
|
||||
else if (opt == 'C') {
|
||||
free(config->cert_file);
|
||||
config->cert_file = strdup(optarg);
|
||||
}
|
||||
|
||||
/* -K SSL key */
|
||||
else if (opt == 'K') {
|
||||
free(config->key_file);
|
||||
config->key_file = strdup(optarg);
|
||||
}
|
||||
#else
|
||||
else if (opt == 'C' || opt == 'K') {
|
||||
fprintf(stderr,
|
||||
"This guacd does not have SSL/TLS support compiled in.\n\n"
|
||||
|
||||
"If you wish to enable support for the -%c option, please install libssl and\n"
|
||||
"recompile guacd.\n",
|
||||
opt);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
|
||||
fprintf(stderr, "USAGE: %s"
|
||||
" [-l LISTENPORT]"
|
||||
" [-b LISTENADDRESS]"
|
||||
" [-p PIDFILE]"
|
||||
" [-L LEVEL]"
|
||||
#ifdef ENABLE_SSL
|
||||
" [-C CERTIFICATE_FILE]"
|
||||
" [-K PEM_FILE]"
|
||||
#endif
|
||||
" [-f]"
|
||||
" [-v]\n", argv[0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
34
src/guacd/conf-args.h
Normal file
34
src/guacd/conf-args.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _GUACD_CONF_ARGS_H
|
||||
#define _GUACD_CONF_ARGS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
/**
|
||||
* Parses the given arguments into the given configuration. Zero is returned on
|
||||
* success, and non-zero is returned if arguments cannot be parsed.
|
||||
*/
|
||||
int guacd_conf_parse_args(guacd_config* config, int argc, char** argv);
|
||||
|
||||
#endif
|
||||
|
216
src/guacd/conf-file.c
Normal file
216
src/guacd/conf-file.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "conf-file.h"
|
||||
#include "conf-parse.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/**
|
||||
* Updates the configuration with the given parameter/value pair, flagging
|
||||
* errors as necessary.
|
||||
*/
|
||||
static int guacd_conf_callback(const char* section, const char* param, const char* value, void* data) {
|
||||
|
||||
guacd_config* config = (guacd_config*) data;
|
||||
|
||||
/* Network server options */
|
||||
if (strcmp(section, "server") == 0) {
|
||||
|
||||
/* Bind host */
|
||||
if (strcmp(param, "bind_host") == 0) {
|
||||
free(config->bind_host);
|
||||
config->bind_host = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind port */
|
||||
else if (strcmp(param, "bind_port") == 0) {
|
||||
free(config->bind_port);
|
||||
config->bind_port = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Options related to daemon startup */
|
||||
else if (strcmp(section, "daemon") == 0) {
|
||||
|
||||
/* PID file */
|
||||
if (strcmp(param, "pid_file") == 0) {
|
||||
free(config->pidfile);
|
||||
config->pidfile = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Max log level */
|
||||
else if (strcmp(param, "log_level") == 0) {
|
||||
|
||||
int level = guacd_parse_log_level(value);
|
||||
|
||||
/* Invalid log level */
|
||||
if (level < 0) {
|
||||
guacd_conf_parse_error = "Invalid log level. Valid levels are: \"trace\", \"debug\", \"info\", \"warning\", and \"error\".";
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Valid log level */
|
||||
config->max_log_level = level;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* SSL-specific options */
|
||||
else if (strcmp(section, "ssl") == 0) {
|
||||
#ifdef ENABLE_SSL
|
||||
/* SSL certificate */
|
||||
if (strcmp(param, "server_certificate") == 0) {
|
||||
free(config->cert_file);
|
||||
config->cert_file = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SSL key */
|
||||
else if (strcmp(param, "server_key") == 0) {
|
||||
free(config->key_file);
|
||||
config->key_file = strdup(value);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
guacd_conf_parse_error = "SSL support not compiled in";
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* If still unhandled, the parameter/section is invalid */
|
||||
guacd_conf_parse_error = "Invalid parameter or section name";
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int guacd_conf_parse_file(guacd_config* conf, int fd) {
|
||||
|
||||
int chars_read;
|
||||
|
||||
char buffer[8192];
|
||||
int length = 0;
|
||||
|
||||
int line = 1;
|
||||
char* line_start = buffer;
|
||||
int parsed = 0;
|
||||
|
||||
/* Attempt to fill remaining space in buffer */
|
||||
while ((chars_read = read(fd, buffer + length, sizeof(buffer) - length)) > 0) {
|
||||
|
||||
length += chars_read;
|
||||
|
||||
line_start = buffer;
|
||||
|
||||
/* Attempt to parse entire buffer */
|
||||
while ((parsed = guacd_parse_conf(guacd_conf_callback, line_start, length, conf)) > 0) {
|
||||
line_start += parsed;
|
||||
length -= parsed;
|
||||
line++;
|
||||
}
|
||||
|
||||
/* Shift contents to front */
|
||||
memmove(buffer, line_start, length);
|
||||
|
||||
}
|
||||
|
||||
/* Handle parse errors */
|
||||
if (parsed < 0) {
|
||||
int column = guacd_conf_parse_error_location - line_start + 1;
|
||||
fprintf(stderr, "Parse error at line %i, column %i: %s.\n",
|
||||
line, column, guacd_conf_parse_error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for error conditions */
|
||||
if (chars_read < 0) {
|
||||
fprintf(stderr, "Error reading configuration: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read successfully */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
guacd_config* guacd_conf_load() {
|
||||
|
||||
guacd_config* conf = malloc(sizeof(guacd_config));
|
||||
if (conf == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Load defaults */
|
||||
conf->bind_host = strdup(GUACD_DEFAULT_BIND_HOST);
|
||||
conf->bind_port = strdup(GUACD_DEFAULT_BIND_PORT);
|
||||
conf->pidfile = NULL;
|
||||
conf->foreground = 0;
|
||||
conf->print_version = 0;
|
||||
conf->max_log_level = GUAC_LOG_INFO;
|
||||
|
||||
#ifdef ENABLE_SSL
|
||||
conf->cert_file = NULL;
|
||||
conf->key_file = NULL;
|
||||
#endif
|
||||
|
||||
/* Read configuration from file */
|
||||
int fd = open(GUACD_CONF_FILE, O_RDONLY);
|
||||
if (fd > 0) {
|
||||
|
||||
int retval = guacd_conf_parse_file(conf, fd);
|
||||
close(fd);
|
||||
|
||||
if (retval != 0) {
|
||||
fprintf(stderr, "Unable to parse \"" GUACD_CONF_FILE "\".\n");
|
||||
free(conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Notify of errors preventing reading */
|
||||
else if (errno != ENOENT) {
|
||||
fprintf(stderr, "Unable to open \"" GUACD_CONF_FILE "\": %s\n", strerror(errno));
|
||||
free(conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
|
||||
}
|
||||
|
41
src/guacd/conf-file.h
Normal file
41
src/guacd/conf-file.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _GUACD_CONF_FILE_H
|
||||
#define _GUACD_CONF_FILE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
/**
|
||||
* Reads the given file descriptor, parsing its contents into the guacd_config.
|
||||
* On success, zero is returned. If parsing fails, non-zero is returned, and an
|
||||
* error message is printed to stderr.
|
||||
*/
|
||||
int guacd_conf_parse_file(guacd_config* conf, int fd);
|
||||
|
||||
/**
|
||||
* Loads the configuration from any of several default locations, if found. If
|
||||
* parsing fails, NULL is returned, and an error message is printed to stderr.
|
||||
*/
|
||||
guacd_config* guacd_conf_load();
|
||||
|
||||
#endif
|
||||
|
537
src/guacd/conf-parse.c
Normal file
537
src/guacd/conf-parse.c
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "conf-parse.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Simple recursive descent parser for an INI-like conf file grammar. The
|
||||
* grammar is, roughly:
|
||||
*
|
||||
* <line> ::= <opt-whitespace> <declaration> <line-end>
|
||||
* <line-end> ::= <opt-whitespace> <opt-comment> <EOL>
|
||||
* <declaration> ::= <section-name> | <parameter-value> | ""
|
||||
* <section-name> ::= "[" <name> "]"
|
||||
* <parameter-value> ::= <name> <opt-whitespace> "=" <opt-whitespace> <value>
|
||||
*
|
||||
* Where:
|
||||
* <opt-whitespace> is any number of tabs or spaces.
|
||||
* <opt-comment> is a # character followed by any length of text without an EOL.
|
||||
* <name> is an alpha-numeric string consisting of: [A-Za-z0-9_-].
|
||||
* <value> is any length of text without an EOL or # character, or a double-quoted string (backslash escapes legal).
|
||||
* <EOL> is a carriage return or line feed character.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The current section. Note that this means the parser is NOT threadsafe.
|
||||
*/
|
||||
char __guacd_current_section[GUACD_CONF_MAX_NAME_LENGTH + 1] = "";
|
||||
|
||||
char* guacd_conf_parse_error = NULL;
|
||||
|
||||
char* guacd_conf_parse_error_location = NULL;
|
||||
|
||||
/**
|
||||
* Reads through all whitespace at the beginning of the buffer, returning the
|
||||
* number of characters read. This is <opt-whitespace> in the grammar above. As
|
||||
* the whitespace is zero or more whitespace characters, this function cannot
|
||||
* fail, but it may read zero chars overall.
|
||||
*/
|
||||
static int guacd_parse_whitespace(char* buffer, int length) {
|
||||
|
||||
int chars_read = 0;
|
||||
|
||||
/* Read through all whitespace */
|
||||
while (chars_read < length) {
|
||||
|
||||
/* Read character */
|
||||
char c = *buffer;
|
||||
|
||||
/* Stop at non-whitespace */
|
||||
if (c != ' ' && c != '\t')
|
||||
break;
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
|
||||
}
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the name of a parameter, section, etc. A section/parameter name can
|
||||
* consist only of alphanumeric characters and underscores. The resulting name
|
||||
* will be stored in the name string, which must have at least 256 bytes
|
||||
* available.
|
||||
*/
|
||||
static int guacd_parse_name(char* buffer, int length, char* name) {
|
||||
|
||||
char* name_start = buffer;
|
||||
int chars_read = 0;
|
||||
|
||||
/* Read through all valid name chars */
|
||||
while (chars_read < length) {
|
||||
|
||||
/* Read character */
|
||||
char c = *buffer;
|
||||
|
||||
/* Stop at non-name characters */
|
||||
if (!isalnum(c) && c != '_')
|
||||
break;
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
|
||||
/* Ensure name does not exceed maximum length */
|
||||
if (chars_read > GUACD_CONF_MAX_NAME_LENGTH) {
|
||||
guacd_conf_parse_error = "Names can be no more than 255 characters long";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Names must contain at least one character */
|
||||
if (chars_read == 0)
|
||||
return 0;
|
||||
|
||||
/* Copy name from buffer */
|
||||
memcpy(name, name_start, chars_read);
|
||||
name[chars_read] = '\0';
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the value of a parameter. A value can consist of any character except
|
||||
* '#', whitespace, or EOL. The resulting value will be stored in the value
|
||||
* string, which must have at least 256 bytes available.
|
||||
*/
|
||||
static int guacd_parse_value(char* buffer, int length, char* value) {
|
||||
|
||||
char* value_start = buffer;
|
||||
int chars_read = 0;
|
||||
|
||||
/* Read through all valid value chars */
|
||||
while (chars_read < length) {
|
||||
|
||||
/* Read character */
|
||||
char c = *buffer;
|
||||
|
||||
/* Stop at invalid character */
|
||||
if (c == '#' || c == '"' || c == '\r' || c == '\n' || c == ' ' || c == '\t')
|
||||
break;
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
|
||||
/* Ensure value does not exceed maximum length */
|
||||
if (chars_read > GUACD_CONF_MAX_VALUE_LENGTH) {
|
||||
guacd_conf_parse_error = "Values can be no more than 8191 characters long";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Values must contain at least one character */
|
||||
if (chars_read == 0) {
|
||||
guacd_conf_parse_error = "Unquoted values must contain at least one character";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy value from buffer */
|
||||
memcpy(value, value_start, chars_read);
|
||||
value[chars_read] = '\0';
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the quoted value of a parameter. Quoted values may contain any
|
||||
* character except double quotes or backslashes, which must be
|
||||
* backslash-escaped.
|
||||
*/
|
||||
static int guacd_parse_quoted_value(char* buffer, int length, char* value) {
|
||||
|
||||
int escaped = 0;
|
||||
|
||||
/* Assert first character is '"' */
|
||||
if (length == 0 || *buffer != '"')
|
||||
return 0;
|
||||
|
||||
int chars_read = 1;
|
||||
buffer++;
|
||||
length--;
|
||||
|
||||
/* Read until end of quoted value */
|
||||
while (chars_read < length) {
|
||||
|
||||
/* Read character */
|
||||
char c = *buffer;
|
||||
|
||||
/* Handle special characters if not escaped */
|
||||
if (!escaped) {
|
||||
|
||||
/* Stop at quote or invalid character */
|
||||
if (c == '"' || c == '\r' || c == '\n')
|
||||
break;
|
||||
|
||||
/* Backslash escaping */
|
||||
else if (c == '\\')
|
||||
escaped = 1;
|
||||
|
||||
else
|
||||
*(value++) = c;
|
||||
|
||||
}
|
||||
|
||||
/* Reset escape flag */
|
||||
else {
|
||||
escaped = 0;
|
||||
*(value++) = c;
|
||||
}
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
|
||||
/* Ensure value does not exceed maximum length */
|
||||
if (chars_read > GUACD_CONF_MAX_VALUE_LENGTH) {
|
||||
guacd_conf_parse_error = "Values can be no more than 8191 characters long";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Assert value ends with '"' */
|
||||
if (length == 0 || *buffer != '"') {
|
||||
guacd_conf_parse_error = "'\"' expected";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read++;
|
||||
|
||||
/* Terminate read value */
|
||||
*value = '\0';
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a parameter/value pair, separated by an '=' character. If the
|
||||
* parameter/value pair is invalid for any reason, a negative value is
|
||||
* returned.
|
||||
*/
|
||||
static int guacd_parse_parameter(guacd_param_callback* callback, char* buffer, int length, void* data) {
|
||||
|
||||
char param_name[GUACD_CONF_MAX_NAME_LENGTH + 1];
|
||||
char param_value[GUACD_CONF_MAX_VALUE_LENGTH + 1];
|
||||
|
||||
int retval;
|
||||
int chars_read = 0;
|
||||
|
||||
char* param_start = buffer;
|
||||
|
||||
retval = guacd_parse_name(buffer, length, param_name);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
/* If no name found, no parameter/value pair */
|
||||
if (retval == 0)
|
||||
return 0;
|
||||
|
||||
/* Validate presence of section header */
|
||||
if (__guacd_current_section[0] == '\0') {
|
||||
guacd_conf_parse_error = "Parameters must have a corresponding section";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Optional whitespace before '=' */
|
||||
retval = guacd_parse_whitespace(buffer, length);
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Required '=' */
|
||||
if (length == 0 || *buffer != '=') {
|
||||
guacd_conf_parse_error = "'=' expected";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
length--;
|
||||
|
||||
/* Optional whitespace before value */
|
||||
retval = guacd_parse_whitespace(buffer, length);
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Quoted parameter value */
|
||||
retval = guacd_parse_quoted_value(buffer, length, param_value);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
/* Non-quoted parameter value (required if no quoted value given) */
|
||||
if (retval == 0) retval = guacd_parse_value(buffer, length, param_value);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
chars_read += retval;
|
||||
|
||||
/* Call callback, handling error code */
|
||||
if (callback(__guacd_current_section, param_name, param_value, data)) {
|
||||
guacd_conf_parse_error_location = param_start;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a section name from the beginning of the given buffer. This section
|
||||
* name must conform to the grammar definition. If the section name does not
|
||||
* match, a negative value is returned.
|
||||
*/
|
||||
static int guacd_parse_section(char* buffer, int length) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Assert first character is '[' */
|
||||
if (length == 0 || *buffer != '[')
|
||||
return 0;
|
||||
|
||||
int chars_read = 1;
|
||||
buffer++;
|
||||
length--;
|
||||
|
||||
retval = guacd_parse_name(buffer, length, __guacd_current_section);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
/* If no name found, invalid section */
|
||||
if (retval == 0) {
|
||||
guacd_conf_parse_error = "Section names must contain at least one character";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Name must end with ']' */
|
||||
if (length == 0 || *buffer != ']') {
|
||||
guacd_conf_parse_error = "']' expected";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read++;
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a declaration, which may be either a section name or a
|
||||
* parameter/value pair. The empty string is acceptable, as well, as a
|
||||
* "null declaration".
|
||||
*/
|
||||
static int guacd_parse_declaration(guacd_param_callback* callback, char* buffer, int length, void* data) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Look for section name */
|
||||
retval = guacd_parse_section(buffer, length);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
|
||||
/* Lacking a section name, read parameter/value pair */
|
||||
retval = guacd_parse_parameter(callback, buffer, length, data);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
|
||||
/* Null declaration (default) */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a comment, which must start with a '#' character, and terminate with
|
||||
* an end-of-line character. If no EOL is found, or the first character is not
|
||||
* a '#', a negative value is returned. Otherwise, the number of characters
|
||||
* parsed is returned. If no comment is present, zero is returned.
|
||||
*/
|
||||
static int guacd_parse_comment(char* buffer, int length) {
|
||||
|
||||
/* Need at least one character */
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
/* Assert first character is '#' */
|
||||
if (*(buffer++) != '#')
|
||||
return 0;
|
||||
|
||||
int chars_read = 1;
|
||||
|
||||
/* Advance to first non-space character */
|
||||
while (chars_read < length) {
|
||||
|
||||
/* Read character */
|
||||
char c = *buffer;
|
||||
|
||||
/* End of comment found at end of line */
|
||||
if (c == '\n' || c == '\r')
|
||||
return chars_read;
|
||||
|
||||
chars_read++;
|
||||
buffer++;
|
||||
|
||||
}
|
||||
|
||||
/* No end of line in comment */
|
||||
guacd_conf_parse_error = "expected end-of-line";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the end of a line, which may contain a comment. If a parse error
|
||||
* occurs, a negative value is returned. Otherwise, the number of characters
|
||||
* parsed is returned.
|
||||
*/
|
||||
static int guacd_parse_line_end(char* buffer, int length) {
|
||||
|
||||
int chars_read = 0;
|
||||
int retval;
|
||||
|
||||
/* Initial optional whitespace */
|
||||
retval = guacd_parse_whitespace(buffer, length);
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Optional comment */
|
||||
retval = guacd_parse_comment(buffer, length);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Assert EOL */
|
||||
if (length == 0 || (*buffer != '\r' && *buffer != '\n')) {
|
||||
guacd_conf_parse_error = "expected end-of-line";
|
||||
guacd_conf_parse_error_location = buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chars_read++;
|
||||
|
||||
/* Line is valid */
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an entire line - declaration, comment, and all. If a parse error
|
||||
* occurs, a negative value is returned. Otherwise, the number of characters
|
||||
* parsed is returned.
|
||||
*/
|
||||
static int guacd_parse_line(guacd_param_callback* callback, char* buffer, int length, void* data) {
|
||||
|
||||
int chars_read = 0;
|
||||
int retval;
|
||||
|
||||
/* Initial optional whitespace */
|
||||
retval = guacd_parse_whitespace(buffer, length);
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* Declaration (which may be the empty string) */
|
||||
retval = guacd_parse_declaration(callback, buffer, length, data);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
chars_read += retval;
|
||||
buffer += retval;
|
||||
length -= retval;
|
||||
|
||||
/* End of line */
|
||||
retval = guacd_parse_line_end(buffer, length);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
chars_read += retval;
|
||||
|
||||
return chars_read;
|
||||
|
||||
}
|
||||
|
||||
int guacd_parse_conf(guacd_param_callback* callback, char* buffer, int length, void* data) {
|
||||
|
||||
/* Empty buffers are valid */
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
return guacd_parse_line(callback, buffer, length, data);
|
||||
|
||||
}
|
||||
|
||||
int guacd_parse_log_level(const char* name) {
|
||||
|
||||
/* Translate log level name */
|
||||
if (strcmp(name, "info") == 0) return GUAC_LOG_INFO;
|
||||
if (strcmp(name, "error") == 0) return GUAC_LOG_ERROR;
|
||||
if (strcmp(name, "warning") == 0) return GUAC_LOG_WARNING;
|
||||
if (strcmp(name, "debug") == 0) return GUAC_LOG_DEBUG;
|
||||
if (strcmp(name, "trace") == 0) return GUAC_LOG_TRACE;
|
||||
|
||||
/* No such log level */
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
68
src/guacd/conf-parse.h
Normal file
68
src/guacd/conf-parse.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef _GUACD_CONF_PARSE_H
|
||||
#define _GUACD_CONF_PARSE_H
|
||||
|
||||
/**
|
||||
* The maximum length of a name, in characters.
|
||||
*/
|
||||
#define GUACD_CONF_MAX_NAME_LENGTH 255
|
||||
|
||||
/**
|
||||
* The maximum length of a value, in characters.
|
||||
*/
|
||||
#define GUACD_CONF_MAX_VALUE_LENGTH 8191
|
||||
|
||||
/**
|
||||
* A callback function which is provided to guacd_parse_conf() and is called
|
||||
* for each parameter/value pair set. The current section is always given. This
|
||||
* function will not be called for parameters outside of sections, which are
|
||||
* illegal.
|
||||
*/
|
||||
typedef int guacd_param_callback(const char* section, const char* param, const char* value, void* data);
|
||||
|
||||
/**
|
||||
* Parses an arbitrary buffer of configuration file data, calling the given
|
||||
* callback for each valid parameter/value pair. Upon success, the number of
|
||||
* characters parsed is returned. On failure, a negative value is returned, and
|
||||
* guacd_conf_parse_error and guacd_conf_parse_error_location are set. The
|
||||
* provided data will be passed to the callback for each invocation.
|
||||
*/
|
||||
int guacd_parse_conf(guacd_param_callback* callback, char* buffer, int length, void* data);
|
||||
|
||||
/**
|
||||
* Parses the given level name, returning the corresponding log level, or -1 if
|
||||
* no such log level exists.
|
||||
*/
|
||||
int guacd_parse_log_level(const char* name);
|
||||
|
||||
/**
|
||||
* Human-readable description of the current error, if any.
|
||||
*/
|
||||
extern char* guacd_conf_parse_error;
|
||||
|
||||
/**
|
||||
* The location of the most recent parse error. This will be a pointer to the
|
||||
* location of the error within the buffer passed to guacd_parse_conf().
|
||||
*/
|
||||
extern char* guacd_conf_parse_error_location;
|
||||
|
||||
#endif
|
||||
|
89
src/guacd/conf.h
Normal file
89
src/guacd/conf.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUACD_CONF_H
|
||||
#define GUACD_CONF_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* The default host that guacd should bind to, if no other host is explicitly
|
||||
* specified.
|
||||
*/
|
||||
#define GUACD_DEFAULT_BIND_HOST "localhost"
|
||||
|
||||
/**
|
||||
* The default port that guacd should bind to, if no other port is explicitly
|
||||
* specified.
|
||||
*/
|
||||
#define GUACD_DEFAULT_BIND_PORT "4822"
|
||||
|
||||
/**
|
||||
* The contents of a guacd configuration file.
|
||||
*/
|
||||
typedef struct guacd_config {
|
||||
|
||||
/**
|
||||
* The host to bind on.
|
||||
*/
|
||||
char* bind_host;
|
||||
|
||||
/**
|
||||
* The port to bind on.
|
||||
*/
|
||||
char* bind_port;
|
||||
|
||||
/**
|
||||
* The file to write the PID in, if any.
|
||||
*/
|
||||
char* pidfile;
|
||||
|
||||
/**
|
||||
* Whether guacd should run in the foreground.
|
||||
*/
|
||||
int foreground;
|
||||
|
||||
/**
|
||||
* Whether guacd should simply print its version information and exit.
|
||||
*/
|
||||
int print_version;
|
||||
|
||||
#ifdef ENABLE_SSL
|
||||
/**
|
||||
* SSL certificate file.
|
||||
*/
|
||||
char* cert_file;
|
||||
|
||||
/**
|
||||
* SSL private key file.
|
||||
*/
|
||||
char* key_file;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The maximum log level to be logged by guacd.
|
||||
*/
|
||||
guac_client_log_level max_log_level;
|
||||
|
||||
} guacd_config;
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user