Compare commits

..

No commits in common. "master" and "0.9.2" have entirely different histories.

664 changed files with 28125 additions and 82948 deletions

View File

@ -1,60 +0,0 @@
# 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
View File

@ -10,10 +10,6 @@
*.gcov
*.gcno
# Test suite output
*.log
*.trs
# Backup files
*~
@ -27,24 +23,32 @@
.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 Normal file
View File

@ -0,0 +1,10 @@
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>

View File

@ -1,52 +0,0 @@
------------------------------------------------------------
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 Normal file
View File

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

View File

@ -1,201 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# 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
View File

@ -1,202 +1,19 @@
Copyright (C) 2013 Glyptodon LLC
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
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:
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of 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.
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.

View File

@ -1,103 +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
# Copyright (C) 2013 Glyptodon LLC
#
# http://www.apache.org/licenses/LICENSE-2.0
# 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:
#
# 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 above copyright notice and this permission notice shall be included in
# all copies or substantial portions of 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.
# 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.
#
ACLOCAL_AMFLAGS = -I m4
# Subprojects
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
DIST_SUBDIRS = \
src/libguac \
src/common \
src/terminal \
src/guacd \
src/protocols/rdp \
src/protocols/ssh \
src/protocols/telnet \
src/protocols/vnc \
tests
SUBDIRS = \
src/libguac \
src/common
if ENABLE_COMMON_SSH
SUBDIRS += src/common-ssh
endif
SUBDIRS = \
src/libguac \
src/common \
src/guacd \
tests
if ENABLE_TERMINAL
SUBDIRS += src/terminal
endif
if ENABLE_PULSE
SUBDIRS += src/pulse
endif
if ENABLE_KUBERNETES
SUBDIRS += src/protocols/kubernetes
SUBDIRS += src/terminal
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
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
EXTRA_DIST = LICENSE doc/Doxyfile bin/guacctl

5
NOTICE
View File

@ -1,5 +0,0 @@
Apache Guacamole
Copyright 2020 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

94
README
View File

@ -4,15 +4,16 @@
------------------------------------------------------------
This README is intended to provide quick and to-the-point documentation for
technical users intending to compile parts of Apache Guacamole themselves.
technical users intending to compile parts of Guacamole themselves.
Source archives are available from the downloads section of the project website:
Distribution-specific packages are available from the files section of the main
project page:
http://guacamole.apache.org/
http://sourceforge.net/projects/guacamole/files/
A full manual is available as well:
Distribution-specific documentation is provided on the Guacamole wiki:
http://guacamole.apache.org/doc/gug/
http://guac-dev.org/
------------------------------------------------------------
@ -25,75 +26,25 @@ 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 text-based protocol was developed which would
desktop) efficiently, a new test-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.
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/.
1) Run configure
@ -144,7 +95,7 @@ guacd itself directly without the init script (as any user):
$ guacd
guacd currently takes several command-line options:
guacd currently takes four command-line options:
-b HOST
@ -160,26 +111,17 @@ guacd currently takes several 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 issue in the JIRA system
Please report any bugs encountered by opening a new ticket at the Trac system
hosted at:
https://issues.apache.org/jira/browse/GUACAMOLE
http://guac-dev.rg/trac/

View File

@ -1,89 +0,0 @@
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.

View File

@ -1,46 +1,44 @@
#!/bin/sh
#
# 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
# Copyright (C) 2013 Glyptodon LLC
#
# http://www.apache.org/licenses/LICENSE-2.0
# 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:
#
# 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 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.
#
#
# guacctl
# -------
#
# Utility for sending Guacamole-specific console codes for controlling a
# terminal session, such as:
# Utility for sending Guacamole-specific console codes for controlling the SSH
# session, such as:
#
# * Downloading files (SSH only)
# * Setting the destination directory for uploads (SSH only)
# * Redirecting output to a named pipe stream (SSH or telnet)
# * Downloading files
# * Setting the destination directory for uploads
#
# 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.
##
## @param FILENAME
## The name of the file to produce the full path of.
##
# Given the name of a file, which may be a relative path, produce the full,
# real, non-relative path for that same file.
fullpath() {
FILENAME="$1"
DIR=`dirname "$FILENAME"`
@ -48,112 +46,44 @@ fullpath() {
(cd "$DIR" && echo "$PWD/$FILE")
}
##
## Sends the Guacamole-specific console code for initiating a download.
##
## @param FILENAME
## The full path of the file to download.
##
# Sends the Guacamole-specific console code for initiating a download.
send_download_file() {
FILENAME="$1"
printf "\033]482200;%s\007" "$FILENAME"
}
##
## Sends the Guacamole-specific console code for setting the upload directory.
##
## @param FILENAME
## The full path to the directory which should receive uploads.
##
# Sends the Guacamole-specific console code for setting the upload directory.
send_set_directory() {
FILENAME="$1"
printf "\033]482201;%s\007" "$FILENAME"
}
##
## 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.
##
# Prints the given error text to STDERR.
error() {
echo "$NAME:" "$@" >&2
}
##
## Prints usage documentation for this script.
##
# Prints usage documentation for this script.
usage() {
cat >&2 <<END
guacctl 1.5.0, Apache Guacamole terminal session control utility.
Usage: guacctl [OPTION] [FILE or NAME]...
guacctl 0.8.0, Guacamole SSH session control utility.
Usage: guacctl [OPTION] [FILE]...
-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.
##
## @param ...
## The name of each file that should be downloaded, as originally
## provided to guacctl.
##
# Initiates a download for each of the specified files
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"`"
@ -164,18 +94,10 @@ download_files() {
}
##
## 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.
##
# Changes the upload path for future uploads to the given directory
set_directory() {
#
# Validate arguments
#
if [ $# -lt 1 ]; then
error "No destination directory specified."
return;
@ -186,10 +108,6 @@ set_directory() {
return;
fi
#
# Send code for setting the upload directory
#
FILENAME="$1"
if [ -d "$FILENAME" ]; then
send_set_directory "`fullpath "$FILENAME"`"
@ -199,170 +117,20 @@ 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"`
#
# Handle downloads directly if invoked as "guacget"
#
# Parse options
if [ "x$NAME" = "xguacget" ]; then
download_files "$@"
exit 0;
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
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

File diff suppressed because it is too large Load Diff

1551
doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# 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

View File

@ -1,60 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# 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

View File

@ -1,5 +0,0 @@
# Auto-generated test runner and binary
_generated_runner.c
test_common_ssh

View File

@ -1,58 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# 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@

View File

@ -1,135 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,134 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,152 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,301 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,155 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,108 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,248 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,602 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,67 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# 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

View File

@ -1,263 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,82 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,5 +0,0 @@
# Auto-generated test runner and binary
_generated_runner.c
test_common

View File

@ -1,71 +1,52 @@
#
# 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
# Copyright (C) 2013 Glyptodon LLC
#
# http://www.apache.org/licenses/LICENSE-2.0
# 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:
#
# 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 above copyright notice and this permission notice shall be included in
# all copies or substantial portions of 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.
# 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.
#
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@
noinst_LTLIBRARIES = libguac_common.la
SUBDIRS = . tests
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
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
libguac_common_la_SOURCES = \
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
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
libguac_common_la_CFLAGS = \
-Werror -Wall -pedantic \
@LIBGUAC_INCLUDE@
libguac_common_la_LIBADD = \
@LIBGUAC_LTLIB@
libguac_common_la_LIBADD = @LIBGUAC_LTLIB@

View File

@ -1,75 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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.");
}

View File

@ -1,166 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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));
}

View File

@ -1,64 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,300 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,31 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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 */

View File

@ -1,261 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,62 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,50 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,196 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,143 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,47 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,539 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,306 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,391 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

102
src/common/guac_clipboard.c Normal file
View File

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

View File

@ -1,20 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* Copyright (C) 2014 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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_CLIPBOARD_H
@ -23,7 +26,6 @@
#include "config.h"
#include <guacamole/client.h>
#include <pthread.h>
/**
* The maximum number of bytes to send in an individual blob when
@ -31,23 +33,11 @@
*/
#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.
*/
@ -71,9 +61,12 @@ typedef struct guac_common_clipboard {
} guac_common_clipboard;
/**
* Creates a new 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.
*/
guac_common_clipboard* guac_common_clipboard_alloc();
guac_common_clipboard* guac_common_clipboard_alloc(int size);
/**
* Frees the given clipboard.

View File

@ -1,20 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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"
@ -24,7 +27,6 @@
#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
@ -50,10 +52,9 @@ unsigned char guac_common_dot_cursor[] = {
};
void guac_common_set_dot_cursor(guac_user* user) {
void guac_common_set_dot_cursor(guac_client* client) {
guac_client* client = user->client;
guac_socket* socket = user->socket;
guac_socket* socket = client->socket;
/* Draw to buffer */
guac_layer* cursor = guac_client_alloc_buffer(client);
@ -65,8 +66,7 @@ void guac_common_set_dot_cursor(guac_user* user) {
guac_common_dot_cursor_height,
guac_common_dot_cursor_stride);
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
0, 0, graphic);
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor, 0, 0, graphic);
cairo_surface_destroy(graphic);
/* Set cursor */
@ -78,8 +78,5 @@ void guac_common_set_dot_cursor(guac_user* user) {
/* Free buffer */
guac_client_free_buffer(client, cursor);
guac_client_log(client, GUAC_LOG_DEBUG,
"Client cursor image set to generic built-in dot.");
}

View File

@ -0,0 +1,64 @@
/*
* 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

195
src/common/guac_iconv.c Normal file
View File

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

View File

@ -1,20 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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_ICONV_H
@ -76,30 +79,6 @@ 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.
*/
@ -120,29 +99,5 @@ 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

71
src/common/guac_io.c Normal file
View File

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

53
src/common/guac_io.h Normal file
View File

@ -0,0 +1,53 @@
/*
* 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

View File

@ -1,24 +1,27 @@
/*
* 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
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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 "common/list.h"
#include "guac_list.h"
#include <stdlib.h>
#include <pthread.h>

View File

@ -1,20 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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_LIST_H

View File

@ -1,20 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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"
@ -24,7 +27,6 @@
#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
@ -61,10 +63,9 @@ unsigned char guac_common_pointer_cursor[] = {
};
void guac_common_set_pointer_cursor(guac_user* user) {
void guac_common_set_pointer_cursor(guac_client* client) {
guac_client* client = user->client;
guac_socket* socket = user->socket;
guac_socket* socket = client->socket;
/* Draw to buffer */
guac_layer* cursor = guac_client_alloc_buffer(client);
@ -76,8 +77,7 @@ void guac_common_set_pointer_cursor(guac_user* user) {
guac_common_pointer_cursor_height,
guac_common_pointer_cursor_stride);
guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor,
0, 0, graphic);
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor, 0, 0, graphic);
cairo_surface_destroy(graphic);
/* Set cursor */
@ -89,8 +89,5 @@ void guac_common_set_pointer_cursor(guac_user* user) {
/* Free buffer */
guac_client_free_buffer(client, cursor);
guac_client_log(client, GUAC_LOG_DEBUG,
"Client cursor image set to generic built-in pointer.");
}

View File

@ -0,0 +1,64 @@
/*
* 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

82
src/common/guac_rect.c Normal file
View File

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

85
src/common/guac_rect.h Normal file
View File

@ -0,0 +1,85 @@
/*
* 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

View File

@ -1,25 +1,28 @@
/*
* 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
* Copyright (C) 2013 Glyptodon LLC
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* 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 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 "common/string.h"
#include "guac_string.h"
#include <stdlib.h>
#include <string.h>

50
src/common/guac_string.h Normal file
View File

@ -0,0 +1,50 @@
/*
* 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

1023
src/common/guac_surface.c Normal file

File diff suppressed because it is too large Load Diff

265
src/common/guac_surface.h Normal file
View File

@ -0,0 +1,265 @@
/*
* 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

View File

@ -1,98 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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.");
}

View File

@ -1,306 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,68 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,180 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,266 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,76 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# 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

View File

@ -1,153 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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"
)
}
};

View File

@ -1,121 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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];

View File

@ -1,129 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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, &current_input, sizeof(input),
writer, &current_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);
}
}
}

View File

@ -1,156 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,43 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,71 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,42 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,39 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,91 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,33 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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'));
}

View File

@ -1,63 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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);
}

View File

@ -1,46 +0,0 @@
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/).

View File

@ -1,115 +0,0 @@
#!/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

View File

@ -1,51 +0,0 @@
#!/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
View File

@ -2,14 +2,42 @@
# Compiled init script
init.d/guacd
# Compiled systemd unit
systemd/guacd.service
# Compiled proxy
guacd
guacd.exe
# Documentation (built from .in files)
man/guacd.8
man/guacd.conf.5
# 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

View File

@ -1,78 +1,45 @@
#
# 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
# Copyright (C) 2013 Glyptodon LLC
#
# http://www.apache.org/licenses/LICENSE-2.0
# 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:
#
# 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 above copyright notice and this permission notice shall be included in
# all copies or substantial portions of 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.
# 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.
#
AUTOMAKE_OPTIONS = foreign
AM_CFLAGS = -Werror -Wall -pedantic @LIBGUAC_INCLUDE@ @COMMON_INCLUDE@
sbin_PROGRAMS = guacd
man_MANS = man/guacd.8
man_MANS = \
man/guacd.8 \
man/guacd.conf.5
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@
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
EXTRA_DIST = init.d/guacd.in man/guacd.8
CLEANFILES = $(init_SCRIPTS)
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)
# SSL support
if ENABLE_SSL
noinst_HEADERS += socket-ssl.h
guacd_SOURCES += socket-ssl.c
endif
# Init script
if ENABLE_INIT
@ -84,12 +51,3 @@ 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

172
src/guacd/client-map.c Normal file
View File

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

73
src/guacd/client-map.h Normal file
View File

@ -0,0 +1,73 @@
/*
* 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

195
src/guacd/client.c Normal file
View File

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

79
src/guacd/client.h Normal file
View File

@ -0,0 +1,79 @@
/*
* 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

View File

@ -1,124 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,34 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,216 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,41 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,537 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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;
}

View File

@ -1,68 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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

View File

@ -1,89 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#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