Initial commit

This commit is contained in:
matt 2020-09-20 12:16:44 +00:00
parent 09a4460ddb
commit 408c005d3e
839 changed files with 190481 additions and 0 deletions

433
BUILDING.txt Normal file
View File

@ -0,0 +1,433 @@
*******************************************************************************
** Building KasmVNC
*******************************************************************************
================================
Build Requirements (All Systems)
================================
-- CMake (http://www.cmake.org) v2.8 or later
-- zlib
-- If building TLS support:
* GnuTLS 3.x
* See "Building TLS Support" below.
-- If building native language support (NLS):
* Gnu gettext 0.14.4 or later
* See "Building Native Language Support" below.
-- libjpeg-turbo
* "Normal" libjpegv6 is also supported, although it is not
recommended as it is much slower.
-- libwebp
=========================
Build Requirements (Unix)
=========================
-- Non-Mac platforms:
* X11 development kit
-- If building Xvnc/libvnc.so:
* Xorg server source code, 1.7 or never
* All build requirements Xorg imposes (see its documentation)
============================
Build Requirements (Windows)
============================
-- MinGW or MinGW-w64
-- Inno Setup (needed to build the KasmVNC installer)
Inno Setup can be downloaded from http://www.jrsoftware.org/isinfo.php.
You also need the Inno Setup Preprocessor, which is available in the
Inno Setup QuickStart Pack.
Add the directory containing iscc.exe (for instance,
C:\Program Files\Inno Setup 5) to the system or user PATH environment
variable prior to building KasmVNC.
==================
Out-of-Tree Builds
==================
Binary objects, libraries, and executables are generated in the same directory
from which cmake was executed (the "binary directory"), and this directory need
not necessarily be the same as the KasmVNC source directory. You can create
multiple independent binary directories, in which different versions of
KasmVNC can be built from the same source tree using different compilers or
settings. In the sections below, {build_directory} refers to the binary
directory, whereas {source_directory} refers to the KasmVNC source directory.
For in-tree builds, these directories are the same.
=================
Building KasmVNC
=================
Building the KasmVNC Server on Modern Unix/Linux Systems
---------------------------------------------------------
Building the KasmVNC Server (Xvnc) is a bit trickier. On newer systems
containing Xorg 7.4 or later (such as Fedora), Xvnc is typically built to use
the X11 shared libraries provided with the system. The procedure for this is
system-specific, since it requires specifying such things as font directories,
but the general outline is as follows.
> cd {build_directory}
If performing an out-of-tree build:
> mkdir unix
> cp -R {source_directory}/unix/xserver unix/
> cp -R {xorg_source}/* unix/xserver/
(NOTE: {xorg_source} is the directory containing the Xorg source for the
machine on which you are building KasmVNC. The most recent versions of
Red Hat/CentOS/Fedora, for instance, provide an RPM called
"xorg-x11-server-source", which installs the Xorg source under
/usr/share/xorg-x11-server-source.)
> cd unix/xserver/
> patch -p1 < {source_directory}/unix/xserver{version}.patch
(where {version} matches the X server version you are building, such as
"17" for version 1.7.x.)
> autoreconf -fiv
> ./configure --with-pic --without-dtrace --disable-static --disable-dri \
--disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \
--disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \
--disable-config-dbus --disable-config-hal --disable-config-udev \
--disable-dri2 --enable-install-libxf86config --enable-glx \
--with-default-font-path="catalogue:/etc/X11/fontpath.d,built-ins" \
--with-fontdir=/usr/share/X11/fonts \
--with-xkb-path=/usr/share/X11/xkb \
--with-xkb-output=/var/lib/xkb \
--with-xkb-bin-directory=/usr/bin \
--with-serverconfig-path=/usr/lib[64]/xorg \
--with-dri-driver-path=/usr/lib[64]/dri \
{additional configure options}
(NOTE: This is merely an example that works with Red Hat Enterprise/CentOS
6 and recent Fedora releases. You should customize it for your particular
system. In particular, it will be necessary to customize the font, XKB,
and DRI directories.)
> make KASMVNC_SRCDIR={source_directory}
Building the KasmVNC Server on Legacy Unix/Linux Systems
---------------------------------------------------------
Those using systems with older versions of Xorg must build a "legacy-friendly"
version of the KasmVNC Server. This is accomplished by downloading and
building the more recent Xorg modules in a local directory and then building
Xvnc such that it links against the local build of these libraries, not the X11
libraries installed on the system. The "build-xorg" script in the KasmVNC
source distribution (located under contrib/xorg/) automates this process.
The following procedure will build a
"legacy-friendly" version of the KasmVNC Server:
cd {build_directory}
sh {source_directory}/contrib/xorg/build-xorg init
sh {source_directory}/contrib/xorg/build-xorg build [additional CMake flags]
build-xorg generates a version of Xvnc that has no external dependencies on the
X11 shared libraries or any other distribution-specific shared libraries. This
version of Xvnc should be transportable across multiple O/S distributions.
build-xorg should work on Red Hat Enterprise 4, its contemporaries, and later
systems. It probably will not work on older systems. It has not been tested
on non-Linux systems (yet).
build-xorg can also be used to rebuild just the KasmVNC Server,
once the X11 modules and other dependencies have been built for the first time.
This is convenient for testing changes that just apply to the KasmVNC source
code. To accomplish this, run:
sh {source_directory}/contrib/xorg/build-xorg rebuild [additional make flags]
For instance,
sh {source_directory}/contrib/xorg/build-xorg rebuild clean
will clean the Xvnc build without destroying any of the
build configuration or module dependencies.
Debug Build
-----------
Add "-DCMAKE_BUILD_TYPE=Debug" to the CMake command line.
Portable (semi-static) Build
----------------------------
KasmVNC can under favourble circumstances be built in a way that allows
the resulting binaries to run on any system without having to also install
all the dynamic libraries it depends on. Enable this mode by adding:
-DBUILD_STATIC=1
to the CMake command line.
Note that the method used to achieve this is very fragile and it may be
necessary to tweak cmake/StaticBuild.cmake to make things work on your
specific system.
======================================
Building TLS Support
======================================
TLS requires GnuTLS, which is supplied with most Linux distributions and
with MinGW for Windows and can be built from source on OS X and other
Unix variants. However, GnuTLS versions > 2.12.x && < 3.3.x should be
avoided because of potential incompatibilities during initial handshaking.
You can override the GNUTLS_LIBRARY and GNUTLS_INCLUDE_DIR CMake variables
to specify the locations of libgnutls and any dependencies. For instance,
adding
-DGNUTLS_INCLUDE_DIR=/usr/local/include \
-DGNUTLS_LIBRARY=/usr/local/lib/libgnutls.a
to the CMake command line would link KasmVNC against a static version of
libgnutls located under /usr/local.
======================================
Building Native Language Support (NLS)
======================================
NLS requires gettext, which is supplied with most Linux distributions and
with MinGW for Windows and which can easily be built from source on OS X and
other Unix variants.
You can override the ICONV_LIBRARIES and LIBINTL_LIBRARY CMake variables to
specify the locations of libiconv and libintl, respectively. For instance,
adding
-DLIBINTL_LIBRARY=/opt/gettext/lib/libintl.a
to the CMake command line would link KasmVNC against a static version of
libintl located under /opt/gettext. Adding
-DICONV_INCLUDE_DIR=/mingw/include \
-DICONV_LIBRARIES=/mingw/lib/libiconv.a \
-DGETTEXT_INCLUDE_DIR=/mingw/include \
-DLIBINTL_LIBRARY=/mingw/lib/libintl.a
to the CMake command line would link KasmVNC against the static versions of
libiconv and libintl included in the MinGW Developer Toolkit.
===================
Installing KasmVNC
===================
You can use the build system to install KasmVNC into a directory of your
choosing. To do this, add:
-DCMAKE_INSTALL_PREFIX={install_directory}
to the CMake command line. Then, you can run 'make install' to build and
install it.
If you don't specify CMAKE_INSTALL_PREFIX, then the default is
c:\Program Files\KasmVNC on Windows and /usr/local on Unix.
=========================
Creating Release Packages
=========================
The following commands can be used to create various types of release packages:
Unix
----
make tarball
Create a binary tarball containing the utils
make servertarball
Create a binary tarball containing both the KasmVNC Server and utils
make dmg
Create Macintosh disk image file that contains an application bundle of the
utils
make udmg
On 64-bit OS X systems, this creates a version of the Macintosh package and
disk image which contains universal i386/x86-64 binaries. You should first
configure a 32-bit out-of-tree build of KasmVNC, then configure a 64-bit
out-of-tree build, then run 'make udmg' from the 64-bit build directory. The
build system will look for the 32-bit build under {source_directory}/osxx86
by default, but you can override this by setting the OSX_X86_BUILD CMake
variable to the directory containing your configured 32-bit build. Either
the 64-bit or 32-bit build can be configured to be backward compatible by
using the instructions in the "Build Recipes" section.
Windows
-------
make installer
Create a Windows installer using Inno Setup. The installer package
(KasmVNC[64].exe) will be located under {build_directory}.
=============
Build Recipes
=============
32-bit Build on 64-bit Linux/Unix (including OS X)
--------------------------------------------------
Set the following environment variables before building KasmVNC.
CFLAGS='-O3 -m32'
CXXFLAGS='-O3 -m32'
LDFLAGS=-m32
If you are building the KasmVNC Server on a modern Unix/Linux system, then
you will also need to pass the appropriate --host argument when configuring the
X server source (for instance, --host=i686-pc-linux-gnu).
64-bit Backward-Compatible Build on 64-bit OS X
-----------------------------------------------
Add
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.5.sdk \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.5
to the CMake command line. The OS X 10.5 SDK must be installed.
32-bit Backward-Compatible Build on 64-bit OS X
-----------------------------------------------
Set the following environment variables:
CC=gcc-4.0
CXX=g++-4.0
CFLAGS='-O3 -m32'
CXXFLAGS='-O3 -m32'
LDFLAGS=-m32
and add
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.4
to the CMake command line. The OS X 10.4 SDK must be installed.
64-bit MinGW Build on Cygwin
----------------------------
cd {build_directory}
CC=/usr/bin/x86_64-w64-mingw32-gcc CXX=/usr/bin/x86_64-w64-mingw32-g++ \
RC=/usr/bin/x86_64-w64-mingw32-windres \
cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_AR=/usr/bin/x86_64-w64-mingw32-ar \
-DCMAKE_RANLIB=/usr/bin/x86_64-w64-mingw32-ranlib {source_directory}
make
This produces a 64-bit build of KasmVNC that does not depend on cygwin1.dll or
other Cygwin DLL's. The mingw64-x86_64-gcc-core and mingw64-x86_64-gcc-g++
packages (and their dependencies) must be installed.
32-bit MinGW Build on Cygwin
----------------------------
cd {build_directory}
CC=/usr/bin/i686-w64-mingw32-gcc CXX=/usr/bin/i686-w64-mingw32-g++ \
RC=/usr/bin/i686-w64-mingw32-windres \
cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
-DDCMAKE_AR=/usr/bin/i686-w64-mingw32-ar \
-DCMAKE_RANLIB=/usr/bin/i686-w64-mingw32-ranlib {source_directory}
make
This produces a 32-bit build of KasmVNC that does not depend on cygwin1.dll or
other Cygwin DLL's. The mingw64-i686-gcc-core and mingw64-i686-gcc-g++
packages (and their dependencies) must be installed.
MinGW-w64 Build on Windows
--------------------------
This produces a 64-bit build of KasmVNC using the "native" MinGW-w64 toolchain
(which is faster than the Cygwin version):
cd {build_directory}
CC={mingw-w64_binary_path}/x86_64-w64-mingw32-gcc \
CXX={mingw-w64_binary_path}/x86_64-w64-mingw32-g++ \
RC={mingw-w64_binary_path}/x86_64-w64-mingw32-windres \
cmake -G "MSYS Makefiles" \
-DCMAKE_AR={mingw-w64_binary_path}/x86_64-w64-mingw32-ar \
-DCMAKE_RANLIB={mingw-w64_binary_path}/x86_64-w64-mingw32-ranlib \
{source_directory}
make
MinGW Build on Linux
--------------------
cd {build_directory}
CC={mingw_binary_path}/i386-mingw32-gcc \
CXX={mingw_binary_path}/i386-mingw32-g++ \
RC={mingw_binary_path}/i386-mingw32-windres \
cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_AR={mingw_binary_path}/i386-mingw32-ar \
-DCMAKE_RANLIB={mingw_binary_path}/i386-mingw32-ranlib \
{source_directory}
make
===============================
Distribution-Specific Packaging
===============================
RPM Packages for RHEL / CentOS
------------------------------
The RPM spec files and patches used to create the nightly builds
and releases can be found in the "contrib/rpm/el{5,6}" directories
of the KasmVNC subversion trunk. All external source tarballs
must be fetched manually and placed into the 'SOURCES' directory
under the rpmbuild root. Additionally, the following macros need
to be defined:
EL6:
%debug_package %{nil}
EL5:
%dist .el5
%_smp_mflags -j3
%debug_package %{nil}
%__arch_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot
Debian packages for Ubuntu 12.04LTS
-----------------------------------
The debian folder used to create the nightly builds and releases
can be found in the "contrib/deb/ubuntu-precise" directory of the
KasmVNC subversion trunk.

242
CMakeLists.txt Normal file
View File

@ -0,0 +1,242 @@
#
# Setup
#
cmake_minimum_required(VERSION 2.8)
if(POLICY CMP0022)
cmake_policy(SET CMP0022 OLD)
endif()
# Internal cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
include(CheckIncludeFiles)
include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckTypeSize)
include(CheckCSourceCompiles)
include(CheckCXXSourceCompiles)
include(CheckCSourceRuns)
include(CMakeMacroLibtoolFile)
project(kasmvnc)
set(VERSION 0.9)
# The RC version must always be four comma-separated numbers
set(RCVERSION 0,9,0,0)
# Installation paths
set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin")
set(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share")
set(MAN_DIR "${DATA_DIR}/man")
set(LOCALE_DIR "${DATA_DIR}/locale")
set(DOC_DIR "${CMAKE_INSTALL_PREFIX}/share/doc/${CMAKE_PROJECT_NAME}-${VERSION}")
if(WIN32)
set(BIN_DIR "${CMAKE_INSTALL_PREFIX}")
set(DOC_DIR "${CMAKE_INSTALL_PREFIX}")
endif()
if(MSVC)
message(FATAL_ERROR "KasmVNC cannot be built with Visual Studio. Please use MinGW")
endif()
if(NOT BUILD_TIMESTAMP)
set(BUILD_TIMESTAMP "")
execute_process(COMMAND "date" "+%Y-%m-%d %H:%M" OUTPUT_VARIABLE BUILD_TIMESTAMP)
string(REGEX REPLACE "\n" "" BUILD_TIMESTAMP ${BUILD_TIMESTAMP})
endif()
# Default to optimised builds instead of debug ones. Our code has no bugs ;)
# (CMake makes it fairly easy to toggle this back to Debug if needed)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
message(STATUS "VERSION = ${VERSION}")
message(STATUS "BUILD_TIMESTAMP = ${BUILD_TIMESTAMP}")
add_definitions(-DBUILD_TIMESTAMP="${BUILD_TIMESTAMP}")
message(STATUS "WWWDIR = ${DATA_DIR}/kasmvnc/www")
add_definitions(-DWWWDIR="${DATA_DIR}/kasmvnc/www")
# We want to keep our asserts even in release builds so remove NDEBUG
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -UNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -UNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -UNDEBUG")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG")
# Make sure we get a sane C version
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
# Enable OpenMP
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
# Tell the compiler to be stringent
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wformat=2")
# Make sure we catch these issues whilst developing
IF(CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
ENDIF()
option(ENABLE_ASAN "Enable address sanitizer support" OFF)
if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif()
option(ENABLE_TSAN "Enable thread sanitizer support" OFF)
if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
endif()
if(NOT DEFINED BUILD_WINVNC)
set(BUILD_WINVNC 1)
endif()
# Minimum version is Windows Vista/2008 (6.0)
if(WIN32)
add_definitions(-D_WIN32_WINNT=0x0600)
endif()
if(CMAKE_SIZEOF_VOID_P MATCHES 8)
message(STATUS "64-bit build")
else()
message(STATUS "32-bit build")
endif()
# Versions of CMake before 2.8.7 do not properly support resource compilation
# with MinGW. Boo!
if(MINGW AND "${CMAKE_VERSION}" VERSION_LESS "2.8.7")
if(NOT DEFINED RC)
set(CMAKE_RC_COMPILER_INIT windres)
else()
set(CMAKE_RC_COMPILER_INIT ${RC})
endif()
enable_language(RC)
message(STATUS "Resource compiler: ${CMAKE_RC_COMPILER}")
set(CMAKE_RC_COMPILE_OBJECT
"<CMAKE_RC_COMPILER> <FLAGS> <DEFINES> -o <OBJECT> --output-format=coff <SOURCE>")
endif()
# MinGW64 has header support but no library support for IActiveDesktop, so we
# need to check for both the header and library and use our own implementation
# in common/os if either doesn't exist.
if(WIN32)
check_c_source_compiles("#include <windows.h>\n#include <wininet.h>\n#include <shlobj.h>\nint main(int c, char** v) {IActiveDesktop iad; (void)iad; return 0;}" HAVE_ACTIVE_DESKTOP_H)
check_c_source_compiles("#include <windows.h>\n#include <wininet.h>\n#include <shlobj.h>\nint main(int c, char** v) {GUID i = CLSID_ActiveDesktop; (void)i; return 0;}" HAVE_ACTIVE_DESKTOP_L)
endif()
# X11 stuff. It's in a if() so that we can say REQUIRED
if(UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
endif()
# Check for zlib
find_package(ZLIB REQUIRED)
# Check for libjpeg
find_package(JPEG REQUIRED)
# Warn if it doesn't seem to be the accelerated libjpeg that's found
set(CMAKE_REQUIRED_LIBRARIES ${JPEG_LIBRARIES})
set(CMAKE_REQUIRED_FLAGS -I${JPEG_INCLUDE_DIR})
set(JPEG_TEST_SOURCE "\n
#include <stdio.h>\n
#include <jpeglib.h>\n
int main(void) {\n
struct jpeg_compress_struct cinfo;\n
struct jpeg_error_mgr jerr;\n
cinfo.err=jpeg_std_error(&jerr);\n
jpeg_create_compress(&cinfo);\n
cinfo.input_components = 3;\n
jpeg_set_defaults(&cinfo);\n
cinfo.in_color_space = JCS_EXT_RGB;\n
jpeg_default_colorspace(&cinfo);\n
return 0;\n
}")
if(CMAKE_CROSSCOMPILING)
check_c_source_compiles("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO)
else()
check_c_source_runs("${JPEG_TEST_SOURCE}" FOUND_LIBJPEG_TURBO)
endif()
set(CMAKE_REQUIRED_LIBRARIES)
set(CMAKE_REQUIRED_FLAGS)
set(CMAKE_REQUIRED_DEFINITIONS)
if(NOT FOUND_LIBJPEG_TURBO)
message(STATUS "WARNING: You are not using libjpeg-turbo. Performance will suffer.")
endif()
include_directories(${JPEG_INCLUDE_DIR})
# Check for GNUTLS library
option(ENABLE_GNUTLS "Enable protocol encryption and advanced authentication" ON)
if(ENABLE_GNUTLS)
find_package(GnuTLS)
if (GNUTLS_FOUND)
include_directories(${GNUTLS_INCLUDE_DIR})
add_definitions("-DHAVE_GNUTLS")
add_definitions(${GNUTLS_DEFINITIONS})
endif()
endif()
# Check for PAM library
option(ENABLE_PAM "Enable PAM authentication support" ON)
if(ENABLE_PAM)
check_include_files(security/pam_appl.h HAVE_PAM_H)
set(CMAKE_REQUIRED_LIBRARIES -lpam)
check_function_exists(pam_start HAVE_PAM_START)
set(CMAKE_REQUIRED_LIBRARIES)
if(HAVE_PAM_H AND HAVE_PAM_START)
set(PAM_LIBS pam)
else()
set(ENABLE_PAM 0)
endif()
endif()
set(HAVE_PAM ${ENABLE_PAM})
# Generate config.h and make sure the source finds it
configure_file(config.h.in config.h)
add_definitions(-DHAVE_CONFIG_H)
include_directories(${CMAKE_BINARY_DIR})
include(cmake/StaticBuild.cmake)
add_subdirectory(common)
if(WIN32)
add_subdirectory(win)
else()
# No interest in building x related parts on Apple
if(NOT APPLE)
add_subdirectory(unix)
endif()
endif()
if(ENABLE_NLS)
add_subdirectory(po)
endif()
add_subdirectory(tests)
include(cmake/BuildPackages.cmake)
# uninstall
configure_file("${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P cmake_uninstall.cmake)

340
LICENCE.TXT Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

194
README.md Normal file
View File

@ -0,0 +1,194 @@
# KasmVNC - Linux Web Remote Desktop
[![Kasm Technologies](https://kasm-static-content.s3.amazonaws.com/368_kasm_logo_.jpg "Kasm Logo")](https://kasmweb.com)
[Kasm Technologies LLC](https://www.kasmweb.com) developed Kasm Server, a Containerized Desktop Infrastructure (CDI) solution. Kasm started with TigerVNC and eventually forked it to create KasmVNC. KasmVNC is used within the overal Kasm CDI infrastructure, however, you can use KasmVNC for individual servers. KasmVNC has different goals than TigerVNC:
- Web-based - KasmVNC is designed to provide a web accessible remote desktop. It comes with a web server and websocket server built in. There is no need to install other components. Simply run and navigate to your desktop's URL on the port you specify. While you can still tun on the legacy VNC port, it is disabled by default.
- Security - KasmVNC defaults to HTTPS and allows for HTTP Basic Auth. VNC Password authentication is limited by specification to 8 characters and is not suffecient for use on an internet accessible remote desktop. Our goal is to create a by default secure, web based experience.
- Simplicity - KasmVNC aims at being simple to deploy and configure.
# New Features!
- Webp image compression for better bandwidth usage
- Automatic mixing of webp and jpeg based on CPU availability on server
- Multi-threaded image encoding for smoother frame rate for servers with more cores
- Full screen video detection, goes into configurable video mode for better full screen videoo playback performance.
- Dynamic jpeg/webp image coompression quality settings based on screen change rates
- Seemless clipboard support
- Allow client to set/change most configuration settings
- Data Loss Prevention features
- Key stroke logging
- Clipboard logging
- Max clipboard transfer size up and down
- Min time between clipboard operations required
- Keyboard input rate limit
Future Goals:
- Support uploads and downloads
- Json configuration file
- Pre-build Packages for all major Linux distributions
- CI pipelines to create releases
### Installation
We are currently developing releasable packages for major operating sytems. The install script available with releases will install dependencies, compile webp, and pull down and install the pre-compiled KasmVNC tarball. Currently, only Ubuntu 18.04 LTS is pre-compiled.
This installer assumes you already have a desktop environment installed, but have never configured a VNC server.
```sh
# download install script from releases
sudo ./install.sh
# change owner of pre-installed cert to your user
sudo chown $USER /usr/local/share/kasmvnc/certs/self.pem
# create required files
touch ~/.Xresources
# start kasmvnc to generate the required files and then kill it
# it will prompt to set the vnc password
vncserver :1 -interface 0.0.0.0
vncserver -kill :1
# overwrite the VNC password to nothing. KasmVNC uses HTTPS basic authentication
echo '' | vncpasswd -f > $HOME/.vnc/passwd
# modify vncstartup to launch your environment of choice, in this example LXDE
echo '/usr/bin/lxsession -s LXDE &' >> ~/.vnc/xstartup
# launch KasmVNC
vncserver $DISPLAY -depth 24 -geometry 1280x1050 -basicAuth kasm_user:password -websocketPort 8443 -cert /usr/local/share/kasmvnc/certs/self.pem -sslOnly -FrameRate=24 -interface 0.0.0.0
```
The options for vncserver in the example above:
| Argument | Description |
| -------- | ----------- |
| depth | Color depth, for jpeg/webp should be 24bit |
| geometry | Screensize, this will automatically be adjusted when the client connects. |
| basicAuth | Username and password seperated by a semi-colon. |
| websocketPort | The port to use for the web socket. Use a high port to avoid having to run as root. |
| cert | SSL cert to use for HTTPS |
| sslOnly | Disable HTTP |
| interface | Which interface to bind the web server to. |
### Development
Would you like to contribute to KasmVNC? Please reachout to us at info@kasmweb.com
We need help, especially in packaging KasmVNC for various operating systems. We would love to have standard debian or RMP packages and host our own repo, however, that all requires a lot of experience, proper testing, and pipeline development for automated builds.
We also need help with Windows, which is not currently supported. While KasmVNC can technically be built for Windows 10, it is unusably slow, due to all the changes that occured in Windows since the original Windows support was added in the chain of VNC forked projects.
### Compiling From Source
See the builder/README.md. We containerize our build systems to ensure highly repeatable builds.
License & Legal
----
Incomplete and generally out of date copyright list::
Copyright (C) 2020 Kasm Technologies LLC
Copyright (C) 1999 AT&T Laboratories Cambridge
Copyright (C) 2002-2005 RealVNC Ltd.
Copyright (C) 2000-2006 TightVNC Group
Copyright (C) 2005-2006 Martin Koegler
Copyright (C) 2005-2006 Sun Microsystems, Inc.
Copyright (C) 2006 OCCAM Financial Technology
Copyright (C) 2000-2008 Constantin Kaplinsky
Copyright (C) 2004-2017 Peter Astrand for Cendio AB
Copyright (C) 2010 Antoine Martin
Copyright (C) 2010 m-privacy GmbH
Copyright (C) 2009-2011 D. R. Commander
Copyright (C) 2009-2011 Pierre Ossman for Cendio AB
Copyright (C) 2004, 2009-2011 Red Hat, Inc.
Copyright (C) 2009-2018 TigerVNC Team
All Rights Reserved.
This software is distributed under the GNU General Public Licence as published
by the Free Software Foundation. See the file LICENCE.TXT for the conditions
under which this software is made available. KasmVNC also contains code from
other sources. See the Acknowledgements section below, and the individual
source files, for details of the conditions under which they are made
available.
### Acknoledgements
This distribution contains zlib compression software. This is:
Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
The data format used by the zlib library is described by RFCs (Request for
Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
This distribution contains public domain DES software by Richard Outerbridge.
This is:
Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
(GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
This distribution contains software from the X Window System. This is:
Copyright 1987, 1988, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
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
OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

30
bitbucket-pipelines.yml Normal file
View File

@ -0,0 +1,30 @@
image: ubuntu:xenial
pipelines:
default:
- step:
name: Build and Package
services:
- docker
script:
- export BASE_DIR="$(readlink -f .)"
- export RELEASE_VERSION=1.9
- export BUILD_FILE="kasmvnc_${RELEASE_VERSION}.${BITBUCKET_COMMIT}.tar.gz"
- export S3_BUILD_DIRECTORY="kasmvnc/${BITBUCKET_COMMIT}"
- export SANITIZED_BRANCH="$(echo $BITBUCKET_BRANCH | sed 's/\//_/g')"
- apt-get update
- apt-get install -y git python3 python3-pip python3-boto3 curl
- echo $SANITIZED_BRANCH
- docker build -t kasmvncbuilder:latest -f builder/dockerfile.build .
- docker run -v $BITBUCKET_CLONE_DIR:/build kasmvncbuilder:latest
- ls -la $BITBUCKET_CLONE_DIR
- ls -la $BITBUCKET_CLONE_DIR/kasmvnc-Linux-x86_64-*.tar.gz
- git clone https://bitbucket.org/awslabs/amazon-s3-bitbucket-pipelines-python.git
- python3 amazon-s3-bitbucket-pipelines-python/s3_upload.py "${S3_BUCKET}" $BITBUCKET_CLONE_DIR/kasmvnc-Linux-x86_64-*.tar.gz "${S3_BUILD_DIRECTORY}/${BUILD_FILE}"
- export S3_URL="https://${S3_BUCKET}.s3.amazonaws.com/${S3_BUILD_DIRECTORY}/${BUILD_FILE}"
- export BUILD_STATUS="{\"key\":\"doc\", \"state\":\"SUCCESSFUL\", \"name\":\"${BUILD_FILE}\", \"url\":\"${S3_URL}\"}"
- echo ${BITBUCKET_REPO_OWNER}
- echo ${BITBUCKET_REPO_SLUG}
- echo ${BITBUCKET_COMMIT}
- echo ${BB_AUTH_STRING}
- echo ${BUILD_STATUS}
- curl -H "Content-Type:application/json" -X POST --user "${BB_AUTH_STRING}" -d "${BUILD_STATUS}" "https://api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/commit/${BITBUCKET_COMMIT}/statuses/build"

22
builder/README.md Normal file
View File

@ -0,0 +1,22 @@
REQIUREMENTS
Docker CE
# build the docker image
cd /src_code_root
sudo docker build -t kasmvncbuilder:18.04 -f builder/dockerfile.build .
# run the builder
sudo docker run -v /tmp:/build kasmvncbuilder:18.04
# tar will be on /tmp of host
cp /tmp/kasmvnc*.tar.gz builder/
# build test desktop container with new binary installed
cd builder
sudo docker build -t kasmvnctester:18.04 -f dockerfile.test .
# run an instance of the new destkop
sudo docker run -d -p 80:6901 -p 5901:5901 -e VNCOPTIONS="-detectScrolling -PreferBandwidth -DynamicQualityMin=0" kasmvnctester:latest
open browser and point to http://IPAddress/vnc_lite.html
default password is "vncpassword" or use a VNC client

66
builder/build.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/sh -e
# For build-dep to work, the apt sources need to have the source server
#sudo apt-get build-dep xorg-server
#sudo apt-get install cmake git libjpeg-dev libgnutls-dev
# Ubuntu applies a million patches, but here we use upstream to simplify matters
cd /tmp
wget https://www.x.org/archive//individual/xserver/xorg-server-1.18.4.tar.bz2
#git clone https://kasmweb@bitbucket.org/kasmtech/kasmvnc.git
#cd kasmvnc
#git checkout dynjpeg
cd /src
# We only want the server, so FLTK and manual tests aren't useful.
# Alternatively, install fltk 1.3 and its dev packages.
sed -i -e '/find_package(FLTK/s@^@#@' \
-e '/add_subdirectory(tests/s@^@#@' \
CMakeLists.txt
cmake .
make -j5
tar -C unix/xserver -xvf /tmp/xorg-server-1.18.4.tar.bz2 --strip-components=1
cd unix/xserver
patch -Np1 -i ../xserver118.patch
autoreconf -i
# Configuring Xorg is long and has many distro-specific paths.
# The distro paths start after prefix and end with the font path,
# everything after that is based on BUILDING.txt to remove unneeded
# components.
./configure --prefix=/opt/kasmweb \
--with-xkb-path=/usr/share/X11/xkb \
--with-xkb-output=/var/lib/xkb \
--with-xkb-bin-directory=/usr/bin \
--with-default-font-path="/usr/share/fonts/X11/misc,/usr/share/fonts/X11/cyrillic,/usr/share/fonts/X11/100dpi/:unscaled,/usr/share/fonts/X11/75dpi/:unscaled,/usr/share/fonts/X11/Type1,/usr/share/fonts/X11/100dpi,/usr/share/fonts/X11/75dpi,built-ins" \
--with-pic --without-dtrace --disable-static --disable-dri \
--disable-xinerama --disable-xvfb --disable-xnest --disable-xorg \
--disable-dmx --disable-xwin --disable-xephyr --disable-kdrive \
--disable-config-hal --disable-config-udev \
--disable-dri2 --enable-glx --disable-xwayland --disable-dri3
make -j5
# modifications for the servertarball
cd /src
mkdir -p xorg.build/bin
cd xorg.build/bin/
ln -s /src/unix/xserver/hw/vnc/Xvnc Xvnc
cd ..
mkdir -p man/man1
touch man/man1/Xserver.1
touch man/man1/Xvnc.1
mkdir lib
cd lib
ln -s /usr/lib/x86_64-linux-gnu/dri dri
cd /src
sed $'s#pushd $TMPDIR/inst#CWD=$(pwd)\\\ncd $TMPDIR/inst#' release/maketarball > release/maketarball2
sed $'s#popd#cd $CWD#' release/maketarball2 > release/maketarball3
mv release/maketarball3 release/maketarball
make servertarball
cp kasmvnc*.tar.gz /build/

View File

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

View File

@ -0,0 +1,22 @@
FROM ubuntu:16.04
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list
RUN apt-get update && \
apt-get -y install sudo
RUN apt-get -y build-dep xorg-server
RUN apt-get -y install cmake git libjpeg-dev libgnutls-dev vim wget tightvncserver
RUN apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
RUN cd /tmp/libwebp-1.0.2 && ./configure && make && make install
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
COPY . /src
RUN chown -R docker:docker /src
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

29
builder/dockerfile.build Normal file
View File

@ -0,0 +1,29 @@
FROM ubuntu:18.04
RUN sed -i 's$# deb-src$deb-src$' /etc/apt/sources.list
RUN apt-get update && \
apt-get -y install sudo
RUN apt-get -y build-dep xorg-server libxfont-dev
RUN apt-get -y install cmake git libjpeg-dev libgnutls28-dev vim wget tightvncserver
RUN apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev libavcodec-dev libssl-dev
# Additions for webp
RUN cd /tmp && wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
RUN cd /tmp && tar -xzvf /tmp/libwebp-*
RUN cd /tmp/libwebp-1.0.2 && ./configure && make && make install
# Fix for older required libs
RUN cd /tmp && wget http://launchpadlibrarian.net/347526424/libxfont1-dev_1.5.2-4ubuntu2_amd64.deb && \
wget http://launchpadlibrarian.net/347526425/libxfont1_1.5.2-4ubuntu2_amd64.deb && \
dpkg -i libxfont1_1.5.2-4ubuntu2_amd64.deb && \
dpkg -i libxfont1-dev_1.5.2-4ubuntu2_amd64.deb
RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo
COPY . /src
RUN chown -R docker:docker /src
USER docker
ENTRYPOINT ["/src/builder/build.sh"]

12
builder/dockerfile.test Normal file
View File

@ -0,0 +1,12 @@
FROM kasmweb/desktop-deluxe:develop
ENV VNCOPTIONS "-PreferBandwidth -DynamicQualityMin=3 -DynamicQualityMax=7 -detectScrolling"
USER root
COPY kasmvnc-Linux-x86_64-*.tar.gz /tmp/
RUN tar -xzvf /tmp/kasmvnc-Linux-x86_64-*.tar.gz --strip 1 -C /
USER 1000
CMD ["--tail-log"]

79
builder/install/install.sh Executable file
View File

@ -0,0 +1,79 @@
set -e
OS_ID='unknown'
OS_VERSION_ID='unknown'
SUPPORTED='false'
if [[ $EUID -ne 0 ]]; then
echo "This script must ran with sudo"
exit 1
fi
function install_deps_ubuntu_18(){
# install deps and build tools
sudo apt-get update
sudo apt-get -y install libjpeg-dev libpng-dev libtiff-dev libgif-dev build-essential cmake libxfont-dev
wget http://launchpadlibrarian.net/347526424/libxfont1-dev_1.5.2-4ubuntu2_amd64.deb
wget http://launchpadlibrarian.net/347526425/libxfont1_1.5.2-4ubuntu2_amd64.deb
sudo dpkg -i libxfont1*.deb
rm /tmp/libxfont1*.deb
}
function build_webp(){
# build webp
wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.0.2.tar.gz
tar -xzvf /tmp/libwebp-*
cd /tmp/libwebp-1.0.2
./configure
make
sudo make install
cd /
rm -rf /tmp/libwebp*
sudo ldconfig
}
function install_kasmvnc(){
# install kasmvnc
wget -qO- https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/c0ab0111ae47a39720f26a7dd7ac54a3681540f8/kasmvnc_1.9.c0ab0111ae47a39720f26a7dd7ac54a3681540f8.tar.gz | sudo tar xz --strip 1 -C /
#install cert
sudo mkdir /usr/local/share/kasmvnc/certs
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /usr/local/share/kasmvnc/certs/self.pem -out /usr/local/share/kasmvnc/certs/self.pem -subj "/C=US/ST=VA/L=None/O=None/OU=DoFu/CN=kasm/emailAddress=none@none.none"
}
cd /tmp
# Get the OS and version
if [ -f /etc/os-release ] ; then
OS_ID="$(awk -F= '/^ID=/{print $2}' /etc/os-release)"
OS_VERSION_ID="$(awk -F= '/^VERSION_ID/{print $2}' /etc/os-release)"
fi
if [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"16.04"' ] || [ "${OS_VERSION_ID}" == '"18.04"' ] || [ "${OS_VERSION_ID}" == '"20.04"' ]) ; then
if [ "${OS_VERSION_ID}" == '"18.04"' ] ; then
SUPPORTED='true'
install_deps_ubuntu_18
build_webp
install_kasmvnc
fi
fi
if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"9"' ] || [ "${OS_VERSION_ID}" == '"10"' ] ) ; then
#TODO: Add support for debian
echo 'Debian is currently not supported'
fi
if [ "${OS_ID}" == '"centos"' ] && ( [ "${OS_VERSION_ID}" == '"7"' ] || [ "${OS_VERSION_ID}" == '"8"' ] ) ; then
#TODO: Add support for Centos
echo 'CentOS is currently not supported'
fi
if [ "${SUPPORTED}" == "false" ] ; then
echo "Installation Not Supported for this Operating System. You must compile KasmVNC from source."
exit -1
fi
echo "Installation is complete"
echo "Follow the instructions to complete setup"

80
cmake/BuildPackages.cmake Normal file
View File

@ -0,0 +1,80 @@
# This file is included from the top-level CMakeLists.txt. We just store it
# here to avoid cluttering up that file.
#
# Windows installer (Inno Setup)
#
if(WIN32)
if(CMAKE_SIZEOF_VOID_P MATCHES 8)
set(INST_NAME ${CMAKE_PROJECT_NAME}64-${VERSION})
set(INST_DEFS -DWIN64)
else()
set(INST_NAME ${CMAKE_PROJECT_NAME}-${VERSION})
endif()
if(BUILD_WINVNC)
set(INST_DEFS ${INST_DEFS} -DBUILD_WINVNC)
set(INST_DEPS ${INST_DEPS} winvnc4 wm_hooks vncconfig)
endif()
configure_file(release/kasmvnc.iss.in release/kasmvnc.iss)
add_custom_target(installer
iscc -o. ${INST_DEFS} -F${INST_NAME} release/kasmvnc.iss
DEPENDS ${INST_DEPS}
SOURCES release/kasmvnc.iss)
endif() # WIN32
#
# Mac DMG
#
if(APPLE)
set(DEFAULT_OSX_X86_BUILD ${CMAKE_SOURCE_DIR}/osxx86)
set(OSX_X86_BUILD ${DEFAULT_OSX_X86_BUILD} CACHE PATH
"Directory containing 32-bit OS X build to include in universal binaries (default: ${DEFAULT_OSX_X86_BUILD})")
configure_file(release/makemacapp.in release/makemacapp)
configure_file(release/Info.plist.in release/Info.plist)
add_custom_target(dmg sh release/makemacapp
SOURCES release/makemacapp)
add_custom_target(udmg sh release/makemacapp universal
SOURCES release/makemacapp)
endif() # APPLE
#
# Binary tarball
#
if(UNIX)
configure_file(release/maketarball.in release/maketarball)
set(TARBALL_DEPENDS vncpasswd vncconfig)
add_custom_target(tarball sh release/maketarball
DEPENDS ${TARBALL_DEPENDS}
SOURCES release/maketarball)
add_custom_target(servertarball sh release/maketarball server
DEPENDS ${TARBALL_DEPENDS}
SOURCES release/maketarball)
endif() #UNIX
#
# Common
#
install(FILES ${CMAKE_SOURCE_DIR}/LICENCE.TXT DESTINATION ${DOC_DIR})
install(FILES ${CMAKE_SOURCE_DIR}/README.md DESTINATION ${DOC_DIR})

View File

@ -0,0 +1,145 @@
macro(libtool_create_control_file _target)
get_target_property(_target_type ${_target} TYPE)
message("-- Creating static libtool control file for target ${_target}")
# No support for shared libraries, as KasmVNC only needs libtool config
# files for static libraries.
if("${_target_type}" MATCHES "^[^STATIC_LIBRARY]$")
message(ERROR " - trying to use libtool_create_control_file for non-static library target.")
endif()
#
# Parse the target_LIB_DEPENDS variable to determine which libraries to put
# into libtool control file as library dependencies, and handle a few corner
# cases.
#
# First we need to split up any internal entries
set(target_libs "")
foreach(library ${${_target}_LIB_DEPENDS})
if("${library}" MATCHES " ")
string(REPLACE " " ";" lib_list "${library}")
list(APPEND target_libs ${lib_list})
else()
list(APPEND target_libs "${library}")
endif()
endforeach()
set(STATIC_MODE OFF)
foreach(library ${target_libs})
# Assume all entries are shared libs if platform-specific static library
# extension is not matched.
if(NOT "${library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$")
if("${library}" MATCHES ".+\\${CMAKE_SHARED_LIBRARY_SUFFIX}$")
# Shared library extension matched, so extract the path and library
# name, then add the result to the libtool dependency libs. This
# will always be an absolute path, because that's what CMake uses
# internally.
get_filename_component(_shared_lib ${library} NAME_WE)
get_filename_component(_shared_lib_path ${library} PATH)
string(REPLACE "lib" "" _shared_lib ${_shared_lib})
set(_target_dependency_libs "${_target_dependency_libs} -L${_shared_lib_path} -l${_shared_lib}")
else()
# No shared library extension matched. Check whether target is a CMake
# target.
if(TARGET ${library})
# Target is a CMake target, so ignore (CMake targets are static
# libs in KasmVNC.)
elseif(${library} STREQUAL "-Wl,-Bstatic")
# All following libraries should be static
set(STATIC_MODE ON)
elseif(${library} STREQUAL "-Wl,-Bdynamic")
# All following libraries should be dynamic
set(STATIC_MODE OFF)
else()
# Normal library, so use find_library() to attempt to locate the
# library in a system directory.
# Need to remove -l prefix
if (${library} MATCHES "^\\${CMAKE_LINK_LIBRARY_FLAG}")
string(REPLACE ${CMAKE_LINK_LIBRARY_FLAG} "" library ${library})
endif()
if(STATIC_MODE)
set(library ${CMAKE_STATIC_LIBRARY_PREFIX}${library}${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
find_library(FL ${library})
if(FL)
# Found library. Depending on if it's static or not we might
# extract the path and library name, then add the
# result to the libtool dependency libs.
if(STATIC_MODE)
set(_target_dependency_libs "${_target_dependency_libs} ${FL}")
else()
get_filename_component(_shared_lib ${FL} NAME_WE)
get_filename_component(_shared_lib_path ${FL} PATH)
string(REPLACE "lib" "" _shared_lib ${_shared_lib})
set(_target_dependency_libs "${_target_dependency_libs} -L${_shared_lib_path} -l${_shared_lib}")
endif()
else()
# No library found, so ignore target.
endif()
# Need to clear FL to get new results next loop
unset(FL CACHE)
endif()
endif()
else()
# Detected a static library. Check whether the library pathname is
# absolute and, if not, use find_library() to get the absolute path.
get_filename_component(_name ${library} NAME)
string(REPLACE "${_name}" "" _path ${library})
if(NOT "${_path}" STREQUAL "")
# Pathname is absolute, so add it to the libtool library dependencies
# as-is.
set(_target_dependency_libs "${_target_dependency_libs} ${library}")
else()
# Pathname is not absolute, so use find_library() to get the absolute
# path.
find_library(FL ${library})
if(FL)
# Absolute pathname found. Add it.
set(_target_dependency_libs "${_target_dependency_libs} ${FL}")
else()
# No absolute pathname found. Ignore it.
endif()
# Need to clear FL to get new results next loop
unset(FL CACHE)
endif()
endif()
endforeach()
# Write the libtool control file for the static library
set(_lname ${CMAKE_STATIC_LIBRARY_PREFIX}${_target})
set(_laname ${CMAKE_CURRENT_BINARY_DIR}/${_lname}.la)
file(WRITE ${_laname} "# ${_lname}.la - a libtool library file\n# Generated by ltmain.sh (GNU libtool) 2.2.6b\n")
file(APPEND ${_laname} "dlname=''\n\n")
file(APPEND ${_laname} "library_names=''\n\n")
file(APPEND ${_laname} "old_library='${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX}'\n\n")
file(APPEND ${_laname} "inherited_linker_flags=''\n\n")
file(APPEND ${_laname} "dependency_libs=' ${_target_dependency_libs}'\n\n")
file(APPEND ${_laname} "weak_library_names=''\n\n")
file(APPEND ${_laname} "current=\n")
file(APPEND ${_laname} "age=\n")
file(APPEND ${_laname} "revision=\n\n")
file(APPEND ${_laname} "installed=no\n\n")
file(APPEND ${_laname} "shouldnotlink=no\n\n")
file(APPEND ${_laname} "dlopen=''\n")
file(APPEND ${_laname} "dlpreopen=''\n\n")
file(APPEND ${_laname} "libdir='/usr/lib'\n\n")
# Make sure the timestamp is updated to trigger other make invocations
add_custom_command(TARGET ${_target} POST_BUILD COMMAND
"${CMAKE_COMMAND}" -E touch "${_laname}")
# Add custom command to symlink the static library so that autotools finds
# the library in .libs. These are executed after the specified target build.
add_custom_command(TARGET ${_target} POST_BUILD COMMAND
"${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/.libs")
add_custom_command(TARGET ${_target} POST_BUILD COMMAND
"${CMAKE_COMMAND}" -E create_symlink ../${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX} "${CMAKE_CURRENT_BINARY_DIR}/.libs/${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endmacro()

View File

@ -0,0 +1,66 @@
# From: http://gitorious.org/gammu/mainline/blobs/master/cmake/FindIconv.cmake
# - Try to find Iconv
# Once done this will define
#
# ICONV_FOUND - system has Iconv
# ICONV_INCLUDE_DIR - the Iconv include directory
# ICONV_LIBRARIES - Link these to use Iconv
# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
#
include(CheckCCompilerFlag)
include(CheckCXXSourceCompiles)
IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
# Already in cache, be silent
SET(ICONV_FIND_QUIETLY TRUE)
ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c)
IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
SET(ICONV_FOUND TRUE)
ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
IF(ICONV_FOUND)
check_c_compiler_flag("-Werror" ICONV_HAVE_WERROR)
set (CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}")
if(ICONV_HAVE_WERROR)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
endif(ICONV_HAVE_WERROR)
check_c_source_compiles("
#include <iconv.h>
int main(){
iconv_t conv = 0;
const char* in = 0;
size_t ilen = 0;
char* out = 0;
size_t olen = 0;
iconv(conv, &in, &ilen, &out, &olen);
return 0;
}
" ICONV_SECOND_ARGUMENT_IS_CONST )
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}")
ENDIF(ICONV_FOUND)
set(CMAKE_REQUIRED_INCLUDES)
set(CMAKE_REQUIRED_LIBRARIES)
IF(ICONV_FOUND)
IF(NOT ICONV_FIND_QUIETLY)
MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
ENDIF(NOT ICONV_FIND_QUIETLY)
ELSE(ICONV_FOUND)
IF(Iconv_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Iconv")
ENDIF(Iconv_FIND_REQUIRED)
ENDIF(ICONV_FOUND)
MARK_AS_ADVANCED(
ICONV_INCLUDE_DIR
ICONV_LIBRARIES
ICONV_SECOND_ARGUMENT_IS_CONST
)

142
cmake/StaticBuild.cmake Normal file
View File

@ -0,0 +1,142 @@
#
# Best-effort magic that tries to produce semi-static binaries
# (i.e. only depends on "safe" libraries like libc and libX11)
#
# Note that this often fails as there is no way to automatically
# determine the dependencies of the libraries we depend on, and
# a lot of details change with each different build environment.
#
option(BUILD_STATIC
"Link statically against most libraries, if possible" OFF)
option(BUILD_STATIC_GCC
"Link statically against only libgcc and libstdc++" OFF)
if(BUILD_STATIC)
message(STATUS "Attempting to link static binaries...")
set(BUILD_STATIC_GCC 1)
set(JPEG_LIBRARIES "-Wl,-Bstatic -ljpeg -Wl,-Bdynamic")
if(WIN32)
set(ZLIB_LIBRARIES "-Wl,-Bstatic -lz -Wl,-Bdynamic")
endif()
# gettext is included in libc on many unix systems
if(NOT LIBC_HAS_DGETTEXT)
set(GETTEXT_LIBRARIES "-Wl,-Bstatic -lintl -liconv -Wl,-Bdynamic")
endif()
if(GNUTLS_FOUND)
# GnuTLS has historically had different crypto backends
FIND_LIBRARY(GCRYPT_LIBRARY NAMES gcrypt libgcrypt
HINTS ${PC_GNUTLS_LIBDIR} ${PC_GNUTLS_LIBRARY_DIRS})
FIND_LIBRARY(NETTLE_LIBRARY NAMES nettle libnettle
HINTS ${PC_GNUTLS_LIBDIR} ${PC_GNUTLS_LIBRARY_DIRS})
FIND_LIBRARY(TASN1_LIBRARY NAMES tasn1 libtasn1
HINTS ${PC_GNUTLS_LIBDIR} ${PC_GNUTLS_LIBRARY_DIRS})
set(GNUTLS_LIBRARIES "-Wl,-Bstatic -lgnutls")
if(TASN1_LIBRARY)
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -ltasn1")
endif()
if(NETTLE_LIBRARY)
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lnettle -lhogweed -lgmp")
endif()
if(GCRYPT_LIBRARY)
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lgcrypt -lgpg-error")
endif()
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -Wl,-Bdynamic")
if (WIN32)
# GnuTLS uses various crypto-api stuff
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lcrypt32")
# And sockets
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lws2_32")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
# nanosleep() lives here on Solaris
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lrt")
# and socket functions are hidden here
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} -lsocket")
endif()
# GnuTLS uses gettext and zlib, so make sure those are always
# included and in the proper order
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} ${ZLIB_LIBRARIES}")
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} ${GETTEXT_LIBRARIES}")
# The last variables might introduce whitespace, which CMake
# throws a hissy fit about
string(STRIP ${GNUTLS_LIBRARIES} GNUTLS_LIBRARIES)
endif()
if(FLTK_FOUND)
set(FLTK_LIBRARIES "-Wl,-Bstatic -lfltk_images -lpng -ljpeg -lfltk -Wl,-Bdynamic")
if(WIN32)
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} -lcomctl32")
elseif(APPLE)
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} -framework Cocoa")
else()
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} -lm -ldl")
endif()
if(X11_FOUND AND NOT APPLE)
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} ${X11_Xcursor_LIB} ${X11_Xfixes_LIB} -Wl,-Bstatic -lXft -Wl,-Bdynamic -lfontconfig -lXrender -lXext -R/usr/sfw/lib -L=/usr/sfw/lib -lfreetype -lsocket -lnsl")
else()
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} -Wl,-Bstatic -lXcursor -lXfixes -lXft -lfontconfig -lexpat -lfreetype -lpng -lbz2 -lXrender -lXext -lXinerama -Wl,-Bdynamic")
endif()
set(FLTK_LIBRARIES "${FLTK_LIBRARIES} -lX11")
endif()
endif()
# X11 libraries change constantly on Linux systems so we have to link
# them statically, even libXext. libX11 is somewhat stable, although
# even it has had an ABI change once or twice.
if(X11_FOUND AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
set(X11_LIBRARIES "-Wl,-Bstatic -lXext -Wl,-Bdynamic -lX11")
if(X11_XTest_LIB)
set(X11_XTest_LIB "-Wl,-Bstatic -lXtst -Wl,-Bdynamic")
endif()
if(X11_Xdamage_LIB)
set(X11_Xdamage_LIB "-Wl,-Bstatic -lXdamage -Wl,-Bdynamic")
endif()
if(X11_Xrandr_LIB)
set(X11_Xrandr_LIB "-Wl,-Bstatic -lXrandr -lXrender -Wl,-Bdynamic")
endif()
endif()
endif()
if(BUILD_STATIC_GCC)
# This ensures that we don't depend on libstdc++ or libgcc_s
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nodefaultlibs")
set(STATIC_BASE_LIBRARIES "-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic")
if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE)
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-Bstatic -lasan -Wl,-Bdynamic -ldl -lm -lpthread")
endif()
if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8)
# libtsan redefines some C++ symbols which then conflict with a
# statically linked libstdc++. Work around this by allowing multiple
# definitions. The linker will pick the first one (i.e. the one
# from libtsan).
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-z -Wl,muldefs -Wl,-Bstatic -ltsan -Wl,-Bdynamic -ldl -lm")
endif()
if(WIN32)
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lmingw32 -lgcc_eh -lgcc -lmoldname -lmingwex -lmsvcrt")
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -luser32 -lkernel32 -ladvapi32 -lshell32")
# mingw has some fun circular dependencies that requires us to link
# these things again
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lmingw32 -lgcc_eh -lgcc -lmoldname -lmingwex -lmsvcrt")
else()
set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lgcc -lgcc_eh -lc")
endif()
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${STATIC_BASE_LIBRARIES}")
endif()

View File

@ -0,0 +1,24 @@
# This code is from the CMake FAQ
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
list(REVERSE files)
foreach (file ${files})
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
if (EXISTS "$ENV{DESTDIR}${file}")
execute_process(
COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}"
OUTPUT_VARIABLE rm_out
RESULT_VARIABLE rm_retval
)
if(NOT ${rm_retval} EQUAL 0)
message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
endif (NOT ${rm_retval} EQUAL 0)
else (EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
endif (EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

15
common/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
add_subdirectory(os)
add_subdirectory(rdr)
add_subdirectory(network)
add_subdirectory(Xregion)
add_subdirectory(rfb)
# For any convenience libraries that are linked into libvnc.so, we need to
# explicitly build their corresponding sources using PIC. WIN32 is excluded
# because PIC code does not exist on that platform and MinGW complains if -fPIC
# is passed (additionally, libvnc is not used on Windows.)
if(NOT WIN32)
set_target_properties(os rdr network Xregion rfb
PROPERTIES COMPILE_FLAGS -fPIC)
endif()

View File

@ -0,0 +1,6 @@
add_library(Xregion STATIC
Region.c)
if(UNIX)
libtool_create_control_file(Xregion)
endif()

1612
common/Xregion/Region.c Normal file

File diff suppressed because it is too large Load Diff

50
common/Xregion/Xlib.h Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright 1985, 1986, 1987, 1991, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
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
OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/*
* Xlib.h - Header definition and support file for the C subroutine
* interface library (Xlib) to the X Window System Protocol (V11).
* Structures and symbols starting with "_" are private to the library.
*/
#ifndef _X11_XLIB_H_
#define _X11_XLIB_H_
#define NeedFunctionPrototypes 1
#define Bool int
typedef struct {
short x, y;
} XPoint;
typedef struct {
short x, y;
unsigned short width, height;
} XRectangle;
#endif /* _X11_XLIB_H_ */

48
common/Xregion/Xlibint.h Normal file
View File

@ -0,0 +1,48 @@
/*
Copyright 1984, 1985, 1987, 1989, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
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 OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
#ifndef _X11_XLIBINT_H_
#define _X11_XLIBINT_H_ 1
/*
* Xlibint.h - Header definition and support file for the internal
* support routines used by the C subroutine interface
* library (Xlib) to the X Window System.
*
* Warning, there be dragons here....
*/
#include <stdlib.h>
#define Xfree(ptr) free((ptr))
#define Xmalloc(size) malloc((size))
#define Xrealloc(ptr, size) realloc((ptr), (size))
#define Xcalloc(nelem, elsize) calloc((nelem), (elsize))
#endif /* _X11_XLIBINT_H_ */

190
common/Xregion/Xregion.h Normal file
View File

@ -0,0 +1,190 @@
/************************************************************************
Copyright 1987, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
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
OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
#ifndef _X11_XREGION_H_
#define _X11_XREGION_H_
typedef struct {
short x1, x2, y1, y2;
} Box, BOX, BoxRec, *BoxPtr;
typedef struct {
short x, y, width, height;
}RECTANGLE, RectangleRec, *RectanglePtr;
#define TRUE 1
#define FALSE 0
#define MAXSHORT 32767
#define MINSHORT -MAXSHORT
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
/*
* clip region
*/
typedef struct _XRegion {
long size;
long numRects;
BOX *rects;
BOX extents;
} REGION;
/* Xutil.h contains the declaration:
* typedef struct _XRegion *Region;
*/
/* 1 if two BOXs overlap.
* 0 if two BOXs do not overlap.
* Remember, x2 and y2 are not in the region
*/
#define EXTENTCHECK(r1, r2) \
((r1)->x2 > (r2)->x1 && \
(r1)->x1 < (r2)->x2 && \
(r1)->y2 > (r2)->y1 && \
(r1)->y1 < (r2)->y2)
/*
* update region extents
*/
#define EXTENTS(r,idRect){\
if((r)->x1 < (idRect)->extents.x1)\
(idRect)->extents.x1 = (r)->x1;\
if((r)->y1 < (idRect)->extents.y1)\
(idRect)->extents.y1 = (r)->y1;\
if((r)->x2 > (idRect)->extents.x2)\
(idRect)->extents.x2 = (r)->x2;\
if((r)->y2 > (idRect)->extents.y2)\
(idRect)->extents.y2 = (r)->y2;\
}
/*
* Check to see if there is enough memory in the present region.
*/
#define MEMCHECK(reg, rect, firstrect){\
if ((reg)->numRects >= ((reg)->size - 1)){\
BoxPtr tmpRect = Xrealloc ((firstrect), \
(2 * (sizeof(BOX)) * ((reg)->size))); \
if (tmpRect == NULL) \
return(0);\
(firstrect) = tmpRect; \
(reg)->size *= 2;\
(rect) = &(firstrect)[(reg)->numRects];\
}\
}
/* this routine checks to see if the previous rectangle is the same
* or subsumes the new rectangle to add.
*/
#define CHECK_PREVIOUS(Reg, R, Rx1, Ry1, Rx2, Ry2)\
(!(((Reg)->numRects > 0)&&\
((R-1)->y1 == (Ry1)) &&\
((R-1)->y2 == (Ry2)) &&\
((R-1)->x1 <= (Rx1)) &&\
((R-1)->x2 >= (Rx2))))
/* add a rectangle to the given Region */
#define ADDRECT(reg, r, rx1, ry1, rx2, ry2){\
if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&\
CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
(r)->x1 = (rx1);\
(r)->y1 = (ry1);\
(r)->x2 = (rx2);\
(r)->y2 = (ry2);\
EXTENTS((r), (reg));\
(reg)->numRects++;\
(r)++;\
}\
}
/* add a rectangle to the given Region */
#define ADDRECTNOX(reg, r, rx1, ry1, rx2, ry2){\
if ((rx1 < rx2) && (ry1 < ry2) &&\
CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
(r)->x1 = (rx1);\
(r)->y1 = (ry1);\
(r)->x2 = (rx2);\
(r)->y2 = (ry2);\
(reg)->numRects++;\
(r)++;\
}\
}
#define EMPTY_REGION(pReg) pReg->numRects = 0
#define REGION_NOT_EMPTY(pReg) pReg->numRects
#define INBOX(r, x, y) \
( ( ((r).x2 > x)) && \
( ((r).x1 <= x)) && \
( ((r).y2 > y)) && \
( ((r).y1 <= y)) )
/*
* number of points to buffer before sending them off
* to scanlines() : Must be an even number
*/
#define NUMPTSTOBUFFER 200
/*
* used to allocate buffers for points and link
* the buffers together
*/
typedef struct _POINTBLOCK {
XPoint pts[NUMPTSTOBUFFER];
struct _POINTBLOCK *next;
} POINTBLOCK;
#endif /* _X11_XREGION_H_ */

167
common/Xregion/Xutil.h Normal file
View File

@ -0,0 +1,167 @@
/***********************************************************
Copyright 1987, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
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
OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#ifndef _X11_XUTIL_H_
#define _X11_XUTIL_H_
/* You must include <X11/Xlib.h> before including this file */
#include "Xlib.h"
/****** Avoid symbol clash with "real" libX11 ******/
#define XClipBox vncXClipBox
#define XCreateRegion vncXCreateRegion
#define XDestroyRegion vncXDestroyRegion
#define XEmptyRegion vncXEmptyRegion
#define XEqualRegion vncXEqualRegion
#define XIntersectRegion vncXIntersectRegion
#define XOffsetRegion vncXOffsetRegion
#define XPointInRegion vncXPointInRegion
#define XPolygonRegion vncXPolygonRegion
#define XRectInRegion vncXRectInRegion
#define XShrinkRegion vncXShrinkRegion
#define XSubtractRegion vncXSubtractRegion
#define XUnionRectWithRegion vncXUnionRectWithRegion
#define XUnionRegion vncXUnionRegion
#define XXorRegion vncXXorRegion
/*
* opaque reference to Region data type
*/
typedef struct _XRegion *Region;
/* Return values from XRectInRegion() */
#define RectangleOut 0
#define RectangleIn 1
#define RectanglePart 2
extern int XClipBox(
Region /* r */,
XRectangle* /* rect_return */
);
extern Region XCreateRegion(
void
);
extern int XDestroyRegion(
Region /* r */
);
extern int XEmptyRegion(
Region /* r */
);
extern int XEqualRegion(
Region /* r1 */,
Region /* r2 */
);
extern int XIntersectRegion(
Region /* sra */,
Region /* srb */,
Region /* dr_return */
);
extern int XOffsetRegion(
Region /* r */,
int /* dx */,
int /* dy */
);
extern Bool XPointInRegion(
Region /* r */,
int /* x */,
int /* y */
);
extern Region XPolygonRegion(
XPoint* /* points */,
int /* n */,
int /* fill_rule */
);
extern int XRectInRegion(
Region /* r */,
int /* x */,
int /* y */,
unsigned int /* width */,
unsigned int /* height */
);
extern int XShrinkRegion(
Region /* r */,
int /* dx */,
int /* dy */
);
extern int XSubtractRegion(
Region /* sra */,
Region /* srb */,
Region /* dr_return */
);
extern int XUnionRectWithRegion(
XRectangle* /* rectangle */,
Region /* src_region */,
Region /* dest_region_return */
);
extern int XUnionRegion(
Region /* sra */,
Region /* srb */,
Region /* dr_return */
);
extern int XXorRegion(
Region /* sra */,
Region /* srb */,
Region /* dr_return */
);
#endif /* _X11_XUTIL_H_ */

View File

@ -0,0 +1,21 @@
include_directories(${CMAKE_SOURCE_DIR}/common)
set(NETWORK_SOURCES
Socket.cxx
TcpSocket.cxx
websocket.c
websockify.c)
if(NOT WIN32)
set(NETWORK_SOURCES ${NETWORK_SOURCES} UnixSocket.cxx)
endif()
add_library(network STATIC ${NETWORK_SOURCES})
if(WIN32)
target_link_libraries(network ws2_32)
endif()
if(UNIX)
libtool_create_control_file(network)
endif()

183
common/network/Socket.cxx Normal file
View File

@ -0,0 +1,183 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef WIN32
//#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define errorNumber WSAGetLastError()
#else
#define errorNumber errno
#define closesocket close
#include <sys/socket.h>
#endif
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <network/Socket.h>
using namespace network;
// -=- Socket initialisation
static bool socketsInitialised = false;
void network::initSockets() {
if (socketsInitialised)
return;
#ifdef WIN32
WORD requiredVersion = MAKEWORD(2,0);
WSADATA initResult;
if (WSAStartup(requiredVersion, &initResult) != 0)
throw SocketException("unable to initialise Winsock2", errorNumber);
#else
signal(SIGPIPE, SIG_IGN);
#endif
socketsInitialised = true;
}
bool network::isSocketListening(int sock)
{
int listening = 0;
socklen_t listening_size = sizeof(listening);
if (getsockopt(sock, SOL_SOCKET, SO_ACCEPTCONN,
(char *)&listening, &listening_size) < 0)
return false;
return listening != 0;
}
Socket::Socket(int fd)
: instream(0), outstream(0),
isShutdown_(false), queryConnection(false)
{
initSockets();
setFd(fd);
}
Socket::Socket()
: instream(0), outstream(0),
isShutdown_(false), queryConnection(false)
{
initSockets();
}
Socket::~Socket()
{
if (instream && outstream)
closesocket(getFd());
delete instream;
delete outstream;
}
// if shutdown() is overridden then the override MUST call on to here
void Socket::shutdown()
{
isShutdown_ = true;
::shutdown(getFd(), 2);
}
bool Socket::isShutdown() const
{
return isShutdown_;
}
// Was there a "?" in the ConnectionFilter used to accept this Socket?
void Socket::setRequiresQuery()
{
queryConnection = true;
}
bool Socket::requiresQuery() const
{
return queryConnection;
}
void Socket::setFd(int fd)
{
#ifndef WIN32
// - By default, close the socket on exec()
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
instream = new rdr::FdInStream(fd);
outstream = new rdr::FdOutStream(fd);
isShutdown_ = false;
}
SocketListener::SocketListener(int fd)
: fd(fd), filter(0)
{
initSockets();
}
SocketListener::SocketListener()
: fd(-1), filter(0)
{
initSockets();
}
SocketListener::~SocketListener()
{
if (fd != -1)
closesocket(fd);
}
void SocketListener::shutdown()
{
#ifdef WIN32
closesocket(fd);
fd = -1;
#else
::shutdown(fd, 2);
#endif
}
Socket* SocketListener::accept() {
int new_sock = -1;
// Accept an incoming connection
if ((new_sock = ::accept(fd, 0, 0)) < 0)
throw SocketException("unable to accept new connection", errorNumber);
// Create the socket object & check connection is allowed
Socket* s = createSocket(new_sock);
if (filter && !filter->verifyConnection(s)) {
delete s;
return NULL;
}
return s;
}
void SocketListener::listen(int sock)
{
// - Set it to be a listening socket
if (::listen(sock, 5) < 0) {
int e = errorNumber;
closesocket(sock);
throw SocketException("unable to set socket to listening mode", e);
}
fd = sock;
}

160
common/network/Socket.h Normal file
View File

@ -0,0 +1,160 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- Socket.h - abstract base-class for any kind of network stream/socket
#ifndef __NETWORK_SOCKET_H__
#define __NETWORK_SOCKET_H__
#include <list>
#include <limits.h>
#include <rdr/FdInStream.h>
#include <rdr/FdOutStream.h>
#include <rdr/Exception.h>
namespace network {
void initSockets();
bool isSocketListening(int sock);
class Socket {
public:
Socket(int fd);
virtual ~Socket();
rdr::FdInStream &inStream() {return *instream;}
rdr::FdOutStream &outStream() {return *outstream;}
int getFd() {return outstream->getFd();}
void shutdown();
bool isShutdown() const;
virtual bool cork(bool enable) = 0;
// information about the remote end of the socket
virtual char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
virtual char* getPeerEndpoint() = 0; // <address>::<port>
// Was there a "?" in the ConnectionFilter used to accept this Socket?
void setRequiresQuery();
bool requiresQuery() const;
protected:
Socket();
void setFd(int fd);
private:
rdr::FdInStream* instream;
rdr::FdOutStream* outstream;
bool isShutdown_;
bool queryConnection;
};
class ConnectionFilter {
public:
virtual bool verifyConnection(Socket* s) = 0;
virtual ~ConnectionFilter() {}
};
class SocketListener {
public:
SocketListener(int fd);
virtual ~SocketListener();
// shutdown() stops the socket from accepting further connections
void shutdown();
// accept() returns a new Socket object if there is a connection
// attempt in progress AND if the connection passes the filter
// if one is installed. Otherwise, returns 0.
Socket* accept();
virtual int getMyPort() = 0;
// setFilter() applies the specified filter to all new connections
void setFilter(ConnectionFilter* f) {filter = f;}
int getFd() {return fd;}
protected:
SocketListener();
void listen(int fd);
// createSocket() should create a new socket of the correct class
// for the given file descriptor
virtual Socket* createSocket(int fd) = 0;
protected:
int fd;
ConnectionFilter* filter;
};
struct SocketException : public rdr::SystemException {
SocketException(const char* text, int err_) : rdr::SystemException(text, err_) {}
};
class SocketServer {
public:
virtual ~SocketServer() {}
// addSocket() tells the server to serve the Socket. The caller
// retains ownership of the Socket - the only way for the server
// to discard a Socket is by calling shutdown() on it.
// outgoing is set to true if the socket was created by connecting out
// to another host, or false if the socket was created by accept()ing
// an incoming connection.
virtual void addSocket(network::Socket* sock, bool outgoing=false) = 0;
// removeSocket() tells the server to stop serving the Socket. The
// caller retains ownership of the Socket - the server must NOT
// delete the Socket! This call is used mainly to cause per-Socket
// resources to be freed.
virtual void removeSocket(network::Socket* sock) = 0;
// getSockets() gets a list of sockets. This can be used to generate an
// fd_set for calling select().
virtual void getSockets(std::list<network::Socket*>* sockets) = 0;
// processSocketReadEvent() tells the server there is a Socket read event.
// The implementation can indicate that the Socket is no longer active
// by calling shutdown() on it. The caller will then call removeSocket()
// soon after processSocketEvent returns, to allow any pre-Socket
// resources to be tidied up.
virtual void processSocketReadEvent(network::Socket* sock) = 0;
// processSocketReadEvent() tells the server there is a Socket write event.
// This is only necessary if the Socket has been put in non-blocking
// mode and needs this callback to flush the buffer.
virtual void processSocketWriteEvent(network::Socket* sock) = 0;
// checkTimeouts() allows the server to check socket timeouts, etc. The
// return value is the number of milliseconds to wait before
// checkTimeouts() should be called again. If this number is zero then
// there is no timeout and checkTimeouts() should be called the next time
// an event occurs.
virtual int checkTimeouts() = 0;
virtual bool getDisable() {return false;};
};
}
#endif // __NETWORK_SOCKET_H__

1029
common/network/TcpSocket.cxx Normal file

File diff suppressed because it is too large Load Diff

158
common/network/TcpSocket.h Normal file
View File

@ -0,0 +1,158 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- TcpSocket.h - base-class for TCP stream sockets.
// This header also defines the TcpListener class, used
// to listen for incoming socket connections over TCP
//
// NB: Any file descriptors created by the TcpSocket or
// TcpListener classes are close-on-exec if the OS supports
// it. TcpSockets initialised with a caller-supplied fd
// are NOT set to close-on-exec.
#ifndef __NETWORK_TCP_SOCKET_H__
#define __NETWORK_TCP_SOCKET_H__
#include <network/Socket.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h> /* for socklen_t */
#include <netinet/in.h> /* for struct sockaddr_in */
#endif
#include <list>
/* Tunnelling support. */
#define TUNNEL_PORT_OFFSET 5500
namespace network {
/* Tunnelling support. */
int findFreeTcpPort (void);
int getSockPort(int sock);
class TcpSocket : public Socket {
public:
TcpSocket(int sock);
TcpSocket(const char *name, int port);
virtual char* getPeerAddress();
virtual char* getPeerEndpoint();
virtual bool cork(bool enable);
protected:
bool enableNagles(bool enable);
};
class WebSocket : public Socket {
public:
WebSocket(int sock);
virtual char* getPeerAddress();
virtual char* getPeerEndpoint();
virtual bool cork(bool enable) { return true; }
};
class TcpListener : public SocketListener {
public:
TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen);
TcpListener(int sock);
virtual int getMyPort();
static void getMyAddresses(std::list<char*>* result);
protected:
virtual Socket* createSocket(int fd);
};
class WebsocketListener : public SocketListener {
public:
WebsocketListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen,
bool sslonly, const char *cert, const char *basicauth,
const char *httpdir);
virtual int getMyPort();
static void getMyAddresses(std::list<char*>* result);
int internalSocket;
protected:
virtual Socket* createSocket(int fd);
};
void createLocalTcpListeners(std::list<SocketListener*> *listeners,
int port);
void createWebsocketListeners(std::list<SocketListener*> *listeners,
int port,
const char *addr,
bool sslonly,
const char *cert,
const char *basicauth,
const char *httpdir);
void createTcpListeners(std::list<SocketListener*> *listeners,
const char *addr,
int port);
void createTcpListeners(std::list<SocketListener*> *listeners,
const struct addrinfo *ai);
void createWebsocketListeners(std::list<SocketListener*> *listeners,
const struct addrinfo *ai,
bool sslonly,
const char *cert,
const char *basicauth,
const char *httpdir);
typedef struct vnc_sockaddr {
union {
sockaddr sa;
sockaddr_in sin;
sockaddr_in6 sin6;
} u;
} vnc_sockaddr_t;
class TcpFilter : public ConnectionFilter {
public:
TcpFilter(const char* filter);
virtual ~TcpFilter();
virtual bool verifyConnection(Socket* s);
typedef enum {Accept, Reject, Query} Action;
struct Pattern {
Action action;
vnc_sockaddr_t address;
unsigned int prefixlen;
vnc_sockaddr_t mask; // computed from address and prefix
};
static Pattern parsePattern(const char* s);
static char* patternToStr(const Pattern& p);
protected:
std::list<Pattern> filter;
};
}
#endif // __NETWORK_TCP_SOCKET_H__

View File

@ -0,0 +1,171 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (c) 2012 University of Oslo. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
#include <network/UnixSocket.h>
#include <rfb/LogWriter.h>
using namespace network;
using namespace rdr;
static rfb::LogWriter vlog("UnixSocket");
// -=- UnixSocket
UnixSocket::UnixSocket(int sock) : Socket(sock)
{
}
UnixSocket::UnixSocket(const char *path)
{
int sock, err, result;
sockaddr_un addr;
socklen_t salen;
if (strlen(path) >= sizeof(addr.sun_path))
throw SocketException("socket path is too long", ENAMETOOLONG);
// - Create a socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
throw SocketException("unable to create socket", errno);
// - Attempt to connect
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
salen = sizeof(addr);
while ((result = connect(sock, (sockaddr *)&addr, salen)) == -1) {
err = errno;
close(sock);
break;
}
if (result == -1)
throw SocketException("unable connect to socket", err);
setFd(sock);
}
char* UnixSocket::getPeerAddress() {
struct sockaddr_un addr;
socklen_t salen;
// AF_UNIX only has a single address (the server side).
// Unfortunately we don't know which end we are, so we'll have to
// test a bit.
salen = sizeof(addr);
if (getpeername(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
vlog.error("unable to get peer name for socket");
return rfb::strDup("");
}
if (salen > offsetof(struct sockaddr_un, sun_path))
return rfb::strDup(addr.sun_path);
salen = sizeof(addr);
if (getsockname(getFd(), (struct sockaddr *)&addr, &salen) != 0) {
vlog.error("unable to get local name for socket");
return rfb::strDup("");
}
if (salen > offsetof(struct sockaddr_un, sun_path))
return rfb::strDup(addr.sun_path);
// socketpair() will create unnamed sockets
return rfb::strDup("(unnamed UNIX socket)");
}
char* UnixSocket::getPeerEndpoint() {
return getPeerAddress();
}
bool UnixSocket::cork(bool enable)
{
return true;
}
UnixListener::UnixListener(const char *path, int mode)
{
struct sockaddr_un addr;
mode_t saved_umask;
int err, result;
if (strlen(path) >= sizeof(addr.sun_path))
throw SocketException("socket path is too long", ENAMETOOLONG);
// - Create a socket
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
throw SocketException("unable to create listening socket", errno);
// - Delete existing socket (ignore result)
unlink(path);
// - Attempt to bind to the requested path
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
saved_umask = umask(0777);
result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
err = errno;
umask(saved_umask);
if (result < 0) {
close(fd);
throw SocketException("unable to bind listening socket", err);
}
// - Set socket mode
if (chmod(path, mode) < 0) {
err = errno;
close(fd);
throw SocketException("unable to set socket mode", err);
}
listen(fd);
}
UnixListener::~UnixListener()
{
struct sockaddr_un addr;
socklen_t salen = sizeof(addr);
if (getsockname(getFd(), (struct sockaddr *)&addr, &salen) == 0)
unlink(addr.sun_path);
}
Socket* UnixListener::createSocket(int fd) {
return new UnixSocket(fd);
}
int UnixListener::getMyPort() {
return 0;
}

View File

@ -0,0 +1,60 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (c) 2012 University of Oslo. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
// -=- UnixSocket.h - base-class for UNIX stream sockets.
// This header also defines the UnixListener class, used
// to listen for incoming socket connections over UNIX
//
// NB: Any file descriptors created by the UnixSocket or
// UnixListener classes are close-on-exec if the OS supports
// it. UnixSockets initialised with a caller-supplied fd
// are NOT set to close-on-exec.
#ifndef __NETWORK_UNIX_SOCKET_H__
#define __NETWORK_UNIX_SOCKET_H__
#include <network/Socket.h>
namespace network {
class UnixSocket : public Socket {
public:
UnixSocket(int sock);
UnixSocket(const char *name);
virtual char* getPeerAddress();
virtual char* getPeerEndpoint();
virtual bool cork(bool enable);
};
class UnixListener : public SocketListener {
public:
UnixListener(const char *listenaddr, int mode);
virtual ~UnixListener();
int getMyPort();
protected:
virtual Socket* createSocket(int fd);
};
}
#endif // __NETWORK_UNIX_SOCKET_H__

1035
common/network/websocket.c Normal file

File diff suppressed because it is too large Load Diff

122
common/network/websocket.h Normal file
View File

@ -0,0 +1,122 @@
#include <openssl/ssl.h>
#define BUFSIZE 65536
#define DBUFSIZE (BUFSIZE * 3) / 4 - 20
#define SERVER_HANDSHAKE_HIXIE "HTTP/1.1 101 Web Socket Protocol Handshake\r\n\
Upgrade: WebSocket\r\n\
Connection: Upgrade\r\n\
%sWebSocket-Origin: %s\r\n\
%sWebSocket-Location: %s://%s%s\r\n\
%sWebSocket-Protocol: %s\r\n\
\r\n%s"
#define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\
Upgrade: websocket\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: %s\r\n\
Sec-WebSocket-Protocol: %s\r\n\
\r\n"
#define HYBI_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define HYBI10_ACCEPTHDRLEN 29
#define HIXIE_MD5_DIGEST_LENGTH 16
#define POLICY_RESPONSE "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\n"
#define OPCODE_TEXT 0x01
#define OPCODE_BINARY 0x02
typedef struct {
char path[1024+1];
char host[1024+1];
char origin[1024+1];
char version[1024+1];
char connection[1024+1];
char protocols[1024+1];
char key1[1024+1];
char key2[1024+1];
char key3[8+1];
} headers_t;
typedef struct {
int sockfd;
SSL_CTX *ssl_ctx;
SSL *ssl;
int hixie;
int hybi;
int opcode;
headers_t *headers;
char *cin_buf;
char *cout_buf;
char *tin_buf;
char *tout_buf;
} ws_ctx_t;
struct wspass_t {
int csock;
unsigned id;
};
typedef struct {
int verbose;
int listen_sock;
unsigned int handler_id;
const char *cert;
const char *key;
const char *basicauth;
int ssl_only;
const char *httpdir;
} settings_t;
#ifdef __cplusplus
extern "C" {
#endif
int resolve_host(struct in_addr *sin_addr, const char *hostname);
ssize_t ws_recv(ws_ctx_t *ctx, void *buf, size_t len);
ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len);
/* base64.c declarations */
//int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
//int b64_pton(char const *src, u_char *target, size_t targsize);
extern __thread unsigned wsthread_handler_id;
#define gen_handler_msg(stream, ...) \
if (settings.verbose) { \
fprintf(stream, " websocket %d: ", wsthread_handler_id); \
fprintf(stream, __VA_ARGS__); \
}
#define wserr(...) \
{ \
fprintf(stderr, " websocket %d: ", wsthread_handler_id); \
fprintf(stderr, __VA_ARGS__); \
}
#define handler_msg(...) gen_handler_msg(stderr, __VA_ARGS__);
#define handler_emsg(...) gen_handler_msg(stderr, __VA_ARGS__);
void traffic(const char * token);
int encode_hixie(u_char const *src, size_t srclength,
char *target, size_t targsize);
int decode_hixie(char *src, size_t srclength,
u_char *target, size_t targsize,
unsigned int *opcode, unsigned int *left);
int encode_hybi(u_char const *src, size_t srclength,
char *target, size_t targsize, unsigned int opcode);
int decode_hybi(unsigned char *src, size_t srclength,
u_char *target, size_t targsize,
unsigned int *opcode, unsigned int *left);
void *start_server(void *unused);
#ifdef __cplusplus
} // extern C
#endif

361
common/network/websockify.c Normal file
View File

@ -0,0 +1,361 @@
/*
* A WebSocket to TCP socket proxy with support for "wss://" encryption.
* Copyright 2010 Joel Martin
* Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
*
* You can make a cert/key with openssl using:
* openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
* as taken from http://docs.python.org/dev/library/ssl.html#certificates
*/
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <getopt.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "websocket.h"
/*
char USAGE[] = "Usage: [options] " \
"[source_addr:]source_port target_addr:target_port\n\n" \
" --verbose|-v verbose messages and per frame traffic\n" \
" --daemon|-D become a daemon (background process)\n" \
" --run-once handle a single WebSocket connection and exit\n" \
" --cert CERT SSL certificate file\n" \
" --key KEY SSL key file (if separate from cert)\n" \
" --ssl-only disallow non-encrypted connections";
*/
extern int pipe_error;
extern settings_t settings;
static void do_proxy(ws_ctx_t *ws_ctx, int target) {
fd_set rlist, wlist, elist;
struct timeval tv;
int maxfd, client = ws_ctx->sockfd;
unsigned int opcode, left, ret;
unsigned int tout_start, tout_end, cout_start, cout_end;
unsigned int tin_start, tin_end;
ssize_t len, bytes;
tout_start = tout_end = cout_start = cout_end =
tin_start = tin_end = 0;
maxfd = client > target ? client+1 : target+1;
while (1) {
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rlist);
FD_ZERO(&wlist);
FD_ZERO(&elist);
FD_SET(client, &elist);
FD_SET(target, &elist);
if (tout_end == tout_start) {
// Nothing queued for target, so read from client
FD_SET(client, &rlist);
} else {
// Data queued for target, so write to it
FD_SET(target, &wlist);
}
if (cout_end == cout_start) {
// Nothing queued for client, so read from target
FD_SET(target, &rlist);
} else {
// Data queued for client, so write to it
FD_SET(client, &wlist);
}
do {
ret = select(maxfd, &rlist, &wlist, &elist, &tv);
} while (ret == -1 && errno == EINTR);
if (pipe_error) { break; }
if (FD_ISSET(target, &elist)) {
handler_emsg("target exception\n");
break;
}
if (FD_ISSET(client, &elist)) {
handler_emsg("client exception\n");
break;
}
if (ret == -1) {
handler_emsg("select(): %s\n", strerror(errno));
break;
} else if (ret == 0) {
//handler_emsg("select timeout\n");
continue;
}
if (FD_ISSET(target, &wlist)) {
len = tout_end-tout_start;
bytes = send(target, ws_ctx->tout_buf + tout_start, len, 0);
if (pipe_error) { break; }
if (bytes < 0) {
handler_emsg("target connection error: %s\n",
strerror(errno));
break;
}
tout_start += bytes;
if (tout_start >= tout_end) {
tout_start = tout_end = 0;
traffic(">");
} else {
traffic(">.");
}
}
if (FD_ISSET(client, &wlist)) {
len = cout_end-cout_start;
bytes = ws_send(ws_ctx, ws_ctx->cout_buf + cout_start, len);
if (pipe_error) { break; }
if (len < 3) {
handler_emsg("len: %d, bytes: %d: %d\n",
(int) len, (int) bytes,
(int) *(ws_ctx->cout_buf + cout_start));
}
cout_start += bytes;
if (cout_start >= cout_end) {
cout_start = cout_end = 0;
traffic("<");
} else {
traffic("<.");
}
}
if (FD_ISSET(target, &rlist)) {
bytes = recv(target, ws_ctx->cin_buf, DBUFSIZE , 0);
if (pipe_error) { break; }
if (bytes <= 0) {
handler_emsg("target closed connection\n");
break;
}
cout_start = 0;
if (ws_ctx->hybi) {
cout_end = encode_hybi(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE, ws_ctx->opcode);
} else {
cout_end = encode_hixie(ws_ctx->cin_buf, bytes,
ws_ctx->cout_buf, BUFSIZE);
}
/*
printf("encoded: ");
for (i=0; i< cout_end; i++) {
printf("%u,", (unsigned char) *(ws_ctx->cout_buf+i));
}
printf("\n");
*/
if (cout_end < 0) {
handler_emsg("encoding error\n");
break;
}
traffic("{");
}
if (FD_ISSET(client, &rlist)) {
bytes = ws_recv(ws_ctx, ws_ctx->tin_buf + tin_end, BUFSIZE-1);
if (pipe_error) { break; }
if (bytes <= 0) {
handler_emsg("client closed connection\n");
break;
}
tin_end += bytes;
/*
printf("before decode: ");
for (i=0; i< bytes; i++) {
printf("%u,", (unsigned char) *(ws_ctx->tin_buf+i));
}
printf("\n");
*/
if (ws_ctx->hybi) {
len = decode_hybi(ws_ctx->tin_buf + tin_start,
tin_end-tin_start,
ws_ctx->tout_buf, BUFSIZE-1,
&opcode, &left);
} else {
len = decode_hixie(ws_ctx->tin_buf + tin_start,
tin_end-tin_start,
ws_ctx->tout_buf, BUFSIZE-1,
&opcode, &left);
}
if (opcode == 8) {
handler_msg("client sent orderly close frame\n");
break;
}
/*
printf("decoded: ");
for (i=0; i< len; i++) {
printf("%u,", (unsigned char) *(ws_ctx->tout_buf+i));
}
printf("\n");
*/
if (len < 0) {
handler_emsg("decoding error\n");
break;
}
if (left) {
tin_start = tin_end - left;
//printf("partial frame from client");
} else {
tin_start = 0;
tin_end = 0;
}
traffic("}");
tout_start = 0;
tout_end = len;
}
}
}
void proxy_handler(ws_ctx_t *ws_ctx) {
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, ".KasmVNCSock");
addr.sun_path[0] = '\0';
int tsock = socket(AF_UNIX, SOCK_STREAM, 0);
handler_msg("connecting to VNC target\n");
if (connect(tsock, (struct sockaddr *) &addr,
sizeof(sa_family_t) + sizeof(".KasmVNCSock")) < 0) {
handler_emsg("Could not connect to target: %s\n",
strerror(errno));
return;
}
do_proxy(ws_ctx, tsock);
shutdown(tsock, SHUT_RDWR);
close(tsock);
}
#if 0
int main(int argc, char *argv[])
{
int fd, c, option_index = 0;
static int ssl_only = 0, daemon = 0, run_once = 0, verbose = 0;
char *found;
static struct option long_options[] = {
{"verbose", no_argument, &verbose, 'v'},
{"ssl-only", no_argument, &ssl_only, 1 },
{"daemon", no_argument, &daemon, 'D'},
/* ---- */
{"run-once", no_argument, 0, 'r'},
{"cert", required_argument, 0, 'c'},
{"key", required_argument, 0, 'k'},
{0, 0, 0, 0}
};
settings.cert = realpath("self.pem", NULL);
if (!settings.cert) {
/* Make sure it's always set to something */
settings.cert = "self.pem";
}
settings.key = "";
while (1) {
c = getopt_long (argc, argv, "vDrc:k:",
long_options, &option_index);
/* Detect the end */
if (c == -1) { break; }
switch (c) {
case 0:
break; // ignore
case 1:
break; // ignore
case 'v':
verbose = 1;
break;
case 'D':
daemon = 1;
break;
case 'r':
run_once = 1;
break;
case 'c':
settings.cert = realpath(optarg, NULL);
if (! settings.cert) {
usage("No cert file at %s\n", optarg);
}
break;
case 'k':
settings.key = realpath(optarg, NULL);
if (! settings.key) {
usage("No key file at %s\n", optarg);
}
break;
default:
usage("");
}
}
settings.verbose = verbose;
settings.ssl_only = ssl_only;
settings.daemon = daemon;
settings.run_once = run_once;
if ((argc-optind) != 2) {
usage("Invalid number of arguments\n");
}
found = strstr(argv[optind], ":");
if (found) {
memcpy(settings.listen_host, argv[optind], found-argv[optind]);
settings.listen_port = strtol(found+1, NULL, 10);
} else {
settings.listen_host[0] = '\0';
settings.listen_port = strtol(argv[optind], NULL, 10);
}
optind++;
if (settings.listen_port == 0) {
usage("Could not parse listen_port\n");
}
found = strstr(argv[optind], ":");
if (found) {
memcpy(target_host, argv[optind], found-argv[optind]);
target_port = strtol(found+1, NULL, 10);
} else {
usage("Target argument must be host:port\n");
}
if (target_port == 0) {
usage("Could not parse target port\n");
}
if (ssl_only) {
if (access(settings.cert, R_OK) != 0) {
usage("SSL only and cert file '%s' not found\n", settings.cert);
}
} else if (access(settings.cert, R_OK) != 0) {
fprintf(stderr, "Warning: '%s' not found\n", settings.cert);
}
//printf(" verbose: %d\n", settings.verbose);
//printf(" ssl_only: %d\n", settings.ssl_only);
//printf(" daemon: %d\n", settings.daemon);
//printf(" run_once: %d\n", settings.run_once);
//printf(" cert: %s\n", settings.cert);
//printf(" key: %s\n", settings.key);
settings.handler = proxy_handler;
start_server();
}
#endif

15
common/os/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
include_directories(${CMAKE_SOURCE_DIR}/common)
add_library(os STATIC
Mutex.cxx
Thread.cxx
w32tiger.c
os.cxx)
if(UNIX)
target_link_libraries(os pthread)
endif()
if(UNIX)
libtool_create_control_file(os)
endif()

154
common/os/Mutex.cxx Normal file
View File

@ -0,0 +1,154 @@
/* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <rdr/Exception.h>
#include <os/Mutex.h>
using namespace os;
Mutex::Mutex()
{
#ifdef WIN32
systemMutex = new CRITICAL_SECTION;
InitializeCriticalSection((CRITICAL_SECTION*)systemMutex);
#else
int ret;
systemMutex = new pthread_mutex_t;
ret = pthread_mutex_init((pthread_mutex_t*)systemMutex, NULL);
if (ret != 0)
throw rdr::SystemException("Failed to create mutex", ret);
#endif
}
Mutex::~Mutex()
{
#ifdef WIN32
DeleteCriticalSection((CRITICAL_SECTION*)systemMutex);
delete (CRITICAL_SECTION*)systemMutex;
#else
pthread_mutex_destroy((pthread_mutex_t*)systemMutex);
delete (pthread_mutex_t*)systemMutex;
#endif
}
void Mutex::lock()
{
#ifdef WIN32
EnterCriticalSection((CRITICAL_SECTION*)systemMutex);
#else
int ret;
ret = pthread_mutex_lock((pthread_mutex_t*)systemMutex);
if (ret != 0)
throw rdr::SystemException("Failed to lock mutex", ret);
#endif
}
void Mutex::unlock()
{
#ifdef WIN32
LeaveCriticalSection((CRITICAL_SECTION*)systemMutex);
#else
int ret;
ret = pthread_mutex_unlock((pthread_mutex_t*)systemMutex);
if (ret != 0)
throw rdr::SystemException("Failed to unlock mutex", ret);
#endif
}
Condition::Condition(Mutex* mutex)
{
this->mutex = mutex;
#ifdef WIN32
systemCondition = new CONDITION_VARIABLE;
InitializeConditionVariable((CONDITION_VARIABLE*)systemCondition);
#else
int ret;
systemCondition = new pthread_cond_t;
ret = pthread_cond_init((pthread_cond_t*)systemCondition, NULL);
if (ret != 0)
throw rdr::SystemException("Failed to create condition variable", ret);
#endif
}
Condition::~Condition()
{
#ifdef WIN32
delete (CONDITION_VARIABLE*)systemCondition;
#else
pthread_cond_destroy((pthread_cond_t*)systemCondition);
delete (pthread_cond_t*)systemCondition;
#endif
}
void Condition::wait()
{
#ifdef WIN32
BOOL ret;
ret = SleepConditionVariableCS((CONDITION_VARIABLE*)systemCondition,
(CRITICAL_SECTION*)mutex->systemMutex,
INFINITE);
if (!ret)
throw rdr::SystemException("Failed to wait on condition variable", GetLastError());
#else
int ret;
ret = pthread_cond_wait((pthread_cond_t*)systemCondition,
(pthread_mutex_t*)mutex->systemMutex);
if (ret != 0)
throw rdr::SystemException("Failed to wait on condition variable", ret);
#endif
}
void Condition::signal()
{
#ifdef WIN32
WakeConditionVariable((CONDITION_VARIABLE*)systemCondition);
#else
int ret;
ret = pthread_cond_signal((pthread_cond_t*)systemCondition);
if (ret != 0)
throw rdr::SystemException("Failed to signal condition variable", ret);
#endif
}
void Condition::broadcast()
{
#ifdef WIN32
WakeAllConditionVariable((CONDITION_VARIABLE*)systemCondition);
#else
int ret;
ret = pthread_cond_broadcast((pthread_cond_t*)systemCondition);
if (ret != 0)
throw rdr::SystemException("Failed to broadcast condition variable", ret);
#endif
}

64
common/os/Mutex.h Normal file
View File

@ -0,0 +1,64 @@
/* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __OS_MUTEX_H__
#define __OS_MUTEX_H__
namespace os {
class Condition;
class Mutex {
public:
Mutex();
~Mutex();
void lock();
void unlock();
private:
friend class Condition;
void* systemMutex;
};
class AutoMutex {
public:
AutoMutex(Mutex* mutex) { m = mutex; m->lock(); }
~AutoMutex() { m->unlock(); }
private:
Mutex* m;
};
class Condition {
public:
Condition(Mutex* mutex);
~Condition();
void wait();
void signal();
void broadcast();
private:
Mutex* mutex;
void* systemCondition;
};
}
#endif

165
common/os/Thread.cxx Normal file
View File

@ -0,0 +1,165 @@
/* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#endif
#include <rdr/Exception.h>
#include <os/Mutex.h>
#include <os/Thread.h>
using namespace os;
Thread::Thread() : running(false), threadId(NULL)
{
mutex = new Mutex;
#ifdef WIN32
threadId = new HANDLE;
#else
threadId = new pthread_t;
#endif
}
Thread::~Thread()
{
#ifdef WIN32
delete (HANDLE*)threadId;
#else
if (isRunning())
pthread_cancel(*(pthread_t*)threadId);
delete (pthread_t*)threadId;
#endif
delete mutex;
}
void Thread::start()
{
AutoMutex a(mutex);
#ifdef WIN32
*(HANDLE*)threadId = CreateThread(NULL, 0, startRoutine, this, 0, NULL);
if (*(HANDLE*)threadId == NULL)
throw rdr::SystemException("Failed to create thread", GetLastError());
#else
int ret;
sigset_t all, old;
// Creating threads from libraries is a bit evil, so mitigate the
// issue by at least avoiding signals on these threads
sigfillset(&all);
ret = pthread_sigmask(SIG_SETMASK, &all, &old);
if (ret != 0)
throw rdr::SystemException("Failed to mask signals", ret);
ret = pthread_create((pthread_t*)threadId, NULL, startRoutine, this);
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (ret != 0)
throw rdr::SystemException("Failed to create thread", ret);
#endif
running = true;
}
void Thread::wait()
{
if (!isRunning())
return;
#ifdef WIN32
DWORD ret;
ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE);
if (ret != WAIT_OBJECT_0)
throw rdr::SystemException("Failed to join thread", GetLastError());
#else
int ret;
ret = pthread_join(*(pthread_t*)threadId, NULL);
if (ret != 0)
throw rdr::SystemException("Failed to join thread", ret);
#endif
}
bool Thread::isRunning()
{
AutoMutex a(mutex);
return running;
}
size_t Thread::getSystemCPUCount()
{
#ifdef WIN32
SYSTEM_INFO si;
size_t count;
DWORD mask;
GetSystemInfo(&si);
count = 0;
for (mask = si.dwActiveProcessorMask;mask != 0;mask >>= 1) {
if (mask & 0x1)
count++;
}
if (count > si.dwNumberOfProcessors)
count = si.dwNumberOfProcessors;
return count;
#else
long ret;
ret = sysconf(_SC_NPROCESSORS_ONLN);
if (ret == -1)
return 0;
return ret;
#endif
}
#ifdef WIN32
long unsigned __stdcall Thread::startRoutine(void* data)
#else
void* Thread::startRoutine(void* data)
#endif
{
Thread *self;
self = (Thread*)data;
try {
self->worker();
} catch(...) {
}
self->mutex->lock();
self->running = false;
self->mutex->unlock();
return 0;
}

58
common/os/Thread.h Normal file
View File

@ -0,0 +1,58 @@
/* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __OS_THREAD_H__
#define __OS_THREAD_H__
#include <stddef.h>
namespace os {
class Mutex;
class Thread {
public:
Thread();
virtual ~Thread();
void start();
void wait();
bool isRunning();
public:
static size_t getSystemCPUCount();
protected:
virtual void worker() = 0;
private:
#ifdef WIN32
static long unsigned __stdcall startRoutine(void* data);
#else
static void* startRoutine(void* data);
#endif
private:
Mutex *mutex;
bool running;
void *threadId;
};
}
#endif

97
common/os/os.cxx Normal file
View File

@ -0,0 +1,97 @@
/* Copyright (C) 2010 TightVNC Team. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <os/os.h>
#include <assert.h>
#ifndef WIN32
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#else
#include <windows.h>
#include <wininet.h> /* MinGW needs it */
#include <shlobj.h>
#endif
int getvnchomedir(char **dirp)
{
#ifndef WIN32
char *homedir, *dir;
size_t len;
uid_t uid;
struct passwd *passwd;
#else
TCHAR *dir;
BOOL ret;
#endif
assert(dirp != NULL && *dirp == NULL);
#ifndef WIN32
homedir = getenv("HOME");
if (homedir == NULL) {
uid = getuid();
passwd = getpwuid(uid);
if (passwd == NULL) {
/* Do we want emit error msg here? */
return -1;
}
homedir = passwd->pw_dir;
}
len = strlen(homedir);
dir = new char[len+7];
if (dir == NULL)
return -1;
memcpy(dir, homedir, len);
memcpy(dir + len, "/.vnc/\0", 7);
#else
dir = new TCHAR[MAX_PATH];
if (dir == NULL)
return -1;
ret = SHGetSpecialFolderPath(NULL, dir, CSIDL_APPDATA, FALSE);
if (ret == FALSE) {
delete [] dir;
return -1;
}
memcpy(dir+strlen(dir), (TCHAR *)"\\vnc\\\0", 6);
#endif
*dirp = dir;
return 0;
}
int fileexists(char *file)
{
#ifdef WIN32
return (GetFileAttributes(file) == INVALID_FILE_ATTRIBUTES) ? -1 : 0;
#else
return access(file, R_OK);
#endif
}

51
common/os/os.h Normal file
View File

@ -0,0 +1,51 @@
/* Copyright (C) 2010 TightVNC Team. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef OS_OS_H
#define OS_OS_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <os/w32tiger.h>
/*
* Get VNC home directory ($HOME/.vnc or %APPDATA%/vnc/).
* If HOME environment variable is set then it is used.
* Otherwise home directory is obtained via getpwuid function.
*
* Note for Windows:
* This functions returns array of TCHARs, not array of chars.
*
* Returns:
* 0 - Success
* -1 - Failure
*/
int getvnchomedir(char **dirp);
/*
* Check if the file exists
*
* Returns:
* 0 - Success
* -1 - Failure
*/
int fileexists(char *file);
#endif /* OS_OS_H */

33
common/os/w32tiger.c Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (C) 2011 TigerVNC Team. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef WIN32
#define INITGUID
#include <basetyps.h>
#ifndef HAVE_ACTIVE_DESKTOP_L
DEFINE_GUID(CLSID_ActiveDesktop,0x75048700L,0xEF1F,0x11D0,0x98,0x88,0x00,0x60,0x97,0xDE,0xAC,0xF9);
DEFINE_GUID(IID_IActiveDesktop,0xF490EB00L,0x1240,0x11D1,0x98,0x88,0x00,0x60,0x97,0xDE,0xAC,0xF9);
#endif
#endif /* WIN32 */

187
common/os/w32tiger.h Normal file
View File

@ -0,0 +1,187 @@
/* Copyright (C) 2011 TigerVNC Team. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef OS_W32TIGER_H
#define OS_W32TIGER_H
#ifdef WIN32
#include <windows.h>
#include <wininet.h>
#include <shlobj.h>
#include <shlguid.h>
#include <wininet.h>
/* Windows has different names for these */
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
/* MSLLHOOKSTRUCT structure*/
#ifndef LLMHF_INJECTED
#define LLMHF_INJECTED 0x00000001
#endif
/* IActiveDesktop. As of 2011-10-12, MinGW does not define
IActiveDesktop in any way (see tracker 2877129), while MinGW64 is
broken: has the headers but not the lib symbols. */
#ifndef HAVE_ACTIVE_DESKTOP_H
extern const GUID CLSID_ActiveDesktop;
extern const GUID IID_IActiveDesktop;
/* IActiveDesktop::AddUrl */
#define ADDURL_SILENT 0x0001
/* IActiveDesktop::AddDesktopItemWithUI */
#define DTI_ADDUI_DEFAULT 0x00000000
#define DTI_ADDUI_DISPSUBWIZARD 0x00000001
#define DTI_ADDUI_POSITIONITEM 0x00000002
/* IActiveDesktop::ModifyDesktopItem */
#define COMP_ELEM_TYPE 0x00000001
#define COMP_ELEM_CHECKED 0x00000002
#define COMP_ELEM_DIRTY 0x00000004
#define COMP_ELEM_NOSCROLL 0x00000008
#define COMP_ELEM_POS_LEFT 0x00000010
#define COMP_ELEM_POS_TOP 0x00000020
#define COMP_ELEM_SIZE_WIDTH 0x00000040
#define COMP_ELEM_SIZE_HEIGHT 0x00000080
#define COMP_ELEM_POS_ZINDEX 0x00000100
#define COMP_ELEM_SOURCE 0x00000200
#define COMP_ELEM_FRIENDLYNAME 0x00000400
#define COMP_ELEM_SUBSCRIBEDURL 0x00000800
#define COMP_ELEM_ORIGINAL_CSI 0x00001000
#define COMP_ELEM_RESTORED_CSI 0x00002000
#define COMP_ELEM_CURITEMSTATE 0x00004000
#define COMP_ELEM_ALL 0x00007FFF /* OR-ed all COMP_ELEM_ */
/* IActiveDesktop::GetWallpaper */
#define AD_GETWP_BMP 0x00000000
#define AD_GETWP_IMAGE 0x00000001
#define AD_GETWP_LAST_APPLIED 0x00000002
/* IActiveDesktop::ApplyChanges */
#define AD_APPLY_SAVE 0x00000001
#define AD_APPLY_HTMLGEN 0x00000002
#define AD_APPLY_REFRESH 0x00000004
#define AD_APPLY_ALL 0x00000007 /* OR-ed three AD_APPLY_ above */
#define AD_APPLY_FORCE 0x00000008
#define AD_APPLY_BUFFERED_REFRESH 0x00000010
#define AD_APPLY_DYNAMICREFRESH 0x00000020
/* Structures for IActiveDesktop */
typedef struct {
DWORD dwSize;
int iLeft;
int iTop;
DWORD dwWidth;
DWORD dwHeight;
DWORD dwItemState;
} COMPSTATEINFO, *LPCOMPSTATEINFO;
typedef const COMPSTATEINFO *LPCCOMPSTATEINFO;
typedef struct {
DWORD dwSize;
int iLeft;
int iTop;
DWORD dwWidth;
DWORD dwHeight;
int izIndex;
BOOL fCanResize;
BOOL fCanResizeX;
BOOL fCanResizeY;
int iPreferredLeftPercent;
int iPreferredTopPercent;
} COMPPOS, *LPCOMPPOS;
typedef const COMPPOS *LPCCOMPPOS;
typedef struct {
DWORD dwSize;
DWORD dwID;
int iComponentType;
BOOL fChecked;
BOOL fDirty;
BOOL fNoScroll;
COMPPOS cpPos;
WCHAR wszFriendlyName[MAX_PATH];
WCHAR wszSource[INTERNET_MAX_URL_LENGTH];
WCHAR wszSubscribedURL[INTERNET_MAX_URL_LENGTH];
DWORD dwCurItemState;
COMPSTATEINFO csiOriginal;
COMPSTATEINFO csiRestored;
} COMPONENT, *LPCOMPONENT;
typedef const COMPONENT *LPCCOMPONENT;
typedef struct {
DWORD dwSize;
BOOL fEnableComponents;
BOOL fActiveDesktop;
} COMPONENTSOPT, *LPCOMPONENTSOPT;
typedef const COMPONENTSOPT *LPCCOMPONENTSOPT;
typedef struct {
DWORD dwSize;
DWORD dwStyle;
} WALLPAPEROPT, *LPWALLPAPEROPT;
typedef const WALLPAPEROPT *LPCWALLPAPEROPT;
/* WALLPAPEROPT styles */
#define WPSTYLE_CENTER 0x0
#define WPSTYLE_TILE 0x1
#define WPSTYLE_STRETCH 0x2
#define WPSTYLE_MAX 0x3
/* Those two are defined in Windows 7 and newer, we don't need them now */
#if 0
#define WPSTYLE_KEEPASPECT 0x3
#define WPSTYLE_CROPTOFIT 0x4
#endif
#define INTERFACE IActiveDesktop
DECLARE_INTERFACE_(IActiveDesktop, IUnknown)
{
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
STDMETHOD(AddDesktopItem)(THIS_ LPCOMPONENT,DWORD) PURE;
STDMETHOD(AddDesktopItemWithUI)(THIS_ HWND,LPCOMPONENT,DWORD) PURE;
STDMETHOD(AddUrl)(THIS_ HWND,LPCWSTR,LPCOMPONENT,DWORD) PURE;
STDMETHOD(ApplyChanges)(THIS_ DWORD) PURE;
STDMETHOD(GenerateDesktopItemHtml)(THIS_ LPCWSTR,LPCOMPONENT,DWORD) PURE;
STDMETHOD(GetDesktopItem)(THIS_ int,LPCOMPONENT,DWORD) PURE;
STDMETHOD(GetDesktopItemByID)(THIS_ DWORD,LPCOMPONENT,DWORD) PURE;
STDMETHOD(GetDesktopItemBySource)(THIS_ LPCWSTR,LPCOMPONENT,DWORD) PURE;
STDMETHOD(GetDesktopItemCount)(THIS_ LPINT,DWORD) PURE;
STDMETHOD(GetDesktopItemOptions)(THIS_ LPCOMPONENTSOPT,DWORD) PURE;
STDMETHOD(GetPattern)(THIS_ LPWSTR,UINT,DWORD) PURE;
STDMETHOD(GetWallpaper)(THIS_ LPWSTR,UINT,DWORD) PURE;
STDMETHOD(GetWallpaperOptions)(THIS_ LPWALLPAPEROPT,DWORD) PURE;
STDMETHOD(ModifyDesktopItem)(THIS_ LPCCOMPONENT,DWORD) PURE;
STDMETHOD(RemoveDesktopItem)(THIS_ LPCCOMPONENT,DWORD) PURE;
STDMETHOD(SetDesktopItemOptions)(THIS_ LPCCOMPONENTSOPT,DWORD) PURE;
STDMETHOD(SetPattern)(THIS_ LPCWSTR,DWORD) PURE;
STDMETHOD(SetWallpaper)(THIS_ LPCWSTR,DWORD) PURE;
STDMETHOD(SetWallpaperOptions)(THIS_ LPCWALLPAPEROPT,DWORD) PURE;
};
#undef INTERFACE
#endif /* HAVE_ACTIVE_DESKTOP_H */
#endif /* WIN32 */
#endif /* OS_W32TIGER_H */

89
common/os/winerrno.h Normal file
View File

@ -0,0 +1,89 @@
/* Generated with:
cat /usr/i686-pc-mingw32/sys-root/mingw/include/winerror.h \
| awk '/#define WSAE.*WSABASE/{gsub("WSA", ""); print "#undef " $2 "\n#define " $2 " WSA" $2}' \
| egrep -v 'EINTR|EBADF|EACCES|EFAULT|EINVAL|EMFILE|_QOS|PROVIDER|PROCTABLE'
*/
#undef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#undef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
#undef EALREADY
#define EALREADY WSAEALREADY
#undef ENOTSOCK
#define ENOTSOCK WSAENOTSOCK
#undef EDESTADDRREQ
#define EDESTADDRREQ WSAEDESTADDRREQ
#undef EMSGSIZE
#define EMSGSIZE WSAEMSGSIZE
#undef EPROTOTYPE
#define EPROTOTYPE WSAEPROTOTYPE
#undef ENOPROTOOPT
#define ENOPROTOOPT WSAENOPROTOOPT
#undef EPROTONOSUPPORT
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
#undef ESOCKTNOSUPPORT
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
#undef EOPNOTSUPP
#define EOPNOTSUPP WSAEOPNOTSUPP
#undef EPFNOSUPPORT
#define EPFNOSUPPORT WSAEPFNOSUPPORT
#undef EAFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#undef EADDRINUSE
#define EADDRINUSE WSAEADDRINUSE
#undef EADDRNOTAVAIL
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#undef ENETDOWN
#define ENETDOWN WSAENETDOWN
#undef ENETUNREACH
#define ENETUNREACH WSAENETUNREACH
#undef ENETRESET
#define ENETRESET WSAENETRESET
#undef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
#undef ECONNRESET
#define ECONNRESET WSAECONNRESET
#undef ENOBUFS
#define ENOBUFS WSAENOBUFS
#undef EISCONN
#define EISCONN WSAEISCONN
#undef ENOTCONN
#define ENOTCONN WSAENOTCONN
#undef ESHUTDOWN
#define ESHUTDOWN WSAESHUTDOWN
#undef ETOOMANYREFS
#define ETOOMANYREFS WSAETOOMANYREFS
#undef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#undef ECONNREFUSED
#define ECONNREFUSED WSAECONNREFUSED
#undef ELOOP
#define ELOOP WSAELOOP
#undef ENAMETOOLONG
#define ENAMETOOLONG WSAENAMETOOLONG
#undef EHOSTDOWN
#define EHOSTDOWN WSAEHOSTDOWN
#undef EHOSTUNREACH
#define EHOSTUNREACH WSAEHOSTUNREACH
#undef ENOTEMPTY
#define ENOTEMPTY WSAENOTEMPTY
#undef EPROCLIM
#define EPROCLIM WSAEPROCLIM
#undef EUSERS
#define EUSERS WSAEUSERS
#undef EDQUOT
#define EDQUOT WSAEDQUOT
#undef ESTALE
#define ESTALE WSAESTALE
#undef EREMOTE
#define EREMOTE WSAEREMOTE
#undef EDISCON
#define EDISCON WSAEDISCON
#undef ENOMORE
#define ENOMORE WSAENOMORE
#undef ECANCELLED
#define ECANCELLED WSAECANCELLED
#undef EREFUSED
#define EREFUSED WSAEREFUSED

30
common/rdr/CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
include_directories(${CMAKE_SOURCE_DIR}/common ${ZLIB_INCLUDE_DIRS})
add_library(rdr STATIC
Exception.cxx
FdInStream.cxx
FdOutStream.cxx
FileInStream.cxx
HexInStream.cxx
HexOutStream.cxx
InStream.cxx
RandomStream.cxx
TLSException.cxx
TLSInStream.cxx
TLSOutStream.cxx
ZlibInStream.cxx
ZlibOutStream.cxx)
set(RDR_LIBRARIES ${ZLIB_LIBRARIES} os)
if(GNUTLS_FOUND)
set(RDR_LIBRARIES ${RDR_LIBRARIES} ${GNUTLS_LIBRARIES})
endif()
if(WIN32)
set(RDR_LIBRARIES ${RDR_LIBRARIES} ws2_32)
endif()
target_link_libraries(rdr ${RDR_LIBRARIES})
if(UNIX)
libtool_create_control_file(rdr)
endif()

99
common/rdr/Exception.cxx Normal file
View File

@ -0,0 +1,99 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <rdr/Exception.h>
#include <rdr/TLSException.h>
#ifdef _WIN32
#include <tchar.h>
#include <winsock2.h>
#include <windows.h>
#endif
#include <string.h>
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
using namespace rdr;
Exception::Exception(const char *format, ...) {
va_list ap;
va_start(ap, format);
(void) vsnprintf(str_, len, format, ap);
va_end(ap);
}
SystemException::SystemException(const char* s, int err_)
: Exception("%s", s), err(err_)
{
strncat(str_, ": ", len-1-strlen(str_));
#ifdef _WIN32
// Windows error messages are crap, so use unix ones for common errors.
const char* msg = 0;
switch (err) {
case WSAECONNREFUSED: msg = "Connection refused"; break;
case WSAETIMEDOUT: msg = "Connection timed out"; break;
case WSAECONNRESET: msg = "Connection reset by peer"; break;
case WSAECONNABORTED: msg = "Connection aborted"; break;
}
if (msg) {
strncat(str_, msg, len-1-strlen(str_));
} else {
#ifdef UNICODE
WCHAR* tmsg = new WCHAR[len-strlen(str_)];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, err, 0, tmsg, len-1-strlen(str_), 0);
WideCharToMultiByte(CP_ACP, 0, tmsg, wcslen(tmsg)+1,
str_+strlen(str_), len-strlen(str_), 0, 0);
delete [] tmsg;
#else
char* currStr = str_+strlen(str_);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, err, 0, currStr, len-1-strlen(str_), 0);
#endif
int l = strlen(str_);
if ((l >= 2) && (str_[l-2] == '\r') && (str_[l-1] == '\n'))
str_[l-2] = 0;
}
#else
strncat(str_, strerror(err), len-1-strlen(str_));
#endif
strncat(str_, " (", len-1-strlen(str_));
char buf[20];
#ifdef WIN32
if (err < 0)
sprintf(buf, "%x", err);
else
#endif
sprintf(buf,"%d",err);
strncat(str_, buf, len-1-strlen(str_));
strncat(str_, ")", len-1-strlen(str_));
}

55
common/rdr/Exception.h Normal file
View File

@ -0,0 +1,55 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_EXCEPTION_H__
#define __RDR_EXCEPTION_H__
#ifdef __GNUC__
# define __printf_attr(a, b) __attribute__((__format__ (__printf__, a, b)))
#else
# define __printf_attr(a, b)
#endif // __GNUC__
namespace rdr {
struct Exception {
enum { len = 256 };
char str_[len];
Exception(const char *format = 0, ...) __printf_attr(2, 3);
virtual ~Exception() {}
virtual const char* str() const { return str_; }
};
struct SystemException : public Exception {
int err;
SystemException(const char* s, int err_);
};
struct TimedOut : public Exception {
TimedOut() : Exception("Timed out") {}
};
struct EndOfStream : public Exception {
EndOfStream() : Exception("End of stream") {}
};
}
#endif

260
common/rdr/FdInStream.cxx Normal file
View File

@ -0,0 +1,260 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#ifdef _WIN32
#include <winsock2.h>
#define close closesocket
#undef errno
#define errno WSAGetLastError()
#include <os/winerrno.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#ifndef vncmin
#define vncmin(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef vncmax
#define vncmax(a,b) (((a) > (b)) ? (a) : (b))
#endif
/* Old systems have select() in sys/time.h */
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <rdr/FdInStream.h>
#include <rdr/Exception.h>
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 8192,
MIN_BULK_SIZE = 1024 };
FdInStream::FdInStream(int fd_, int timeoutms_, int bufSize_,
bool closeWhenDone_)
: fd(fd_), closeWhenDone(closeWhenDone_),
timeoutms(timeoutms_), blockCallback(0),
timing(false), timeWaitedIn100us(5), timedKbits(0),
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
{
ptr = end = start = new U8[bufSize];
}
FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_,
int bufSize_)
: fd(fd_), timeoutms(0), blockCallback(blockCallback_),
timing(false), timeWaitedIn100us(5), timedKbits(0),
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
{
ptr = end = start = new U8[bufSize];
}
FdInStream::~FdInStream()
{
delete [] start;
if (closeWhenDone) close(fd);
}
void FdInStream::setTimeout(int timeoutms_) {
timeoutms = timeoutms_;
}
void FdInStream::setBlockCallback(FdInStreamBlockCallback* blockCallback_)
{
blockCallback = blockCallback_;
timeoutms = 0;
}
int FdInStream::pos()
{
return offset + ptr - start;
}
void FdInStream::readBytes(void* data, int length)
{
if (length < MIN_BULK_SIZE) {
InStream::readBytes(data, length);
return;
}
U8* dataPtr = (U8*)data;
int n = end - ptr;
if (n > length) n = length;
memcpy(dataPtr, ptr, n);
dataPtr += n;
length -= n;
ptr += n;
while (length > 0) {
n = readWithTimeoutOrCallback(dataPtr, length);
dataPtr += n;
length -= n;
offset += n;
}
}
int FdInStream::overrun(int itemSize, int nItems, bool wait)
{
if (itemSize > bufSize)
throw Exception("FdInStream overrun: max itemSize exceeded");
if (end - ptr != 0)
memmove(start, ptr, end - ptr);
offset += ptr - start;
end -= ptr - start;
ptr = start;
int bytes_to_read;
while (end < start + itemSize) {
bytes_to_read = start + bufSize - end;
if (!timing) {
// When not timing, we must be careful not to read too much
// extra data into the buffer. Otherwise, the line speed
// estimation might stay at zero for a long time: All reads
// during timing=1 can be satisfied without calling
// readWithTimeoutOrCallback. However, reading only 1 or 2 bytes
// bytes is ineffecient.
bytes_to_read = vncmin(bytes_to_read, vncmax(itemSize*nItems, 8));
}
int n = readWithTimeoutOrCallback((U8*)end, bytes_to_read, wait);
if (n == 0) return 0;
end += n;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
//
// readWithTimeoutOrCallback() reads up to the given length in bytes from the
// file descriptor into a buffer. If the wait argument is false, then zero is
// returned if no bytes can be read without blocking. Otherwise if a
// blockCallback is set, it will be called (repeatedly) instead of blocking.
// If alternatively there is a timeout set and that timeout expires, it throws
// a TimedOut exception. Otherwise it returns the number of bytes read. It
// never attempts to recv() unless select() indicates that the fd is readable -
// this means it can be used on an fd which has been set non-blocking. It also
// has to cope with the annoying possibility of both select() and recv()
// returning EINTR.
//
int FdInStream::readWithTimeoutOrCallback(void* buf, int len, bool wait)
{
struct timeval before, after;
if (timing)
gettimeofday(&before, 0);
int n;
while (true) {
do {
fd_set fds;
struct timeval tv;
struct timeval* tvp = &tv;
if (!wait) {
tv.tv_sec = tv.tv_usec = 0;
} else if (timeoutms != -1) {
tv.tv_sec = timeoutms / 1000;
tv.tv_usec = (timeoutms % 1000) * 1000;
} else {
tvp = 0;
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
n = select(fd+1, &fds, 0, 0, tvp);
} while (n < 0 && errno == EINTR);
if (n > 0) break;
if (n < 0) throw SystemException("select",errno);
if (!wait) return 0;
if (!blockCallback) throw TimedOut();
blockCallback->blockCallback();
}
do {
n = ::recv(fd, (char*)buf, len, 0);
} while (n < 0 && errno == EINTR);
if (n < 0) throw SystemException("read",errno);
if (n == 0) throw EndOfStream();
if (timing) {
gettimeofday(&after, 0);
int newTimeWaited = ((after.tv_sec - before.tv_sec) * 10000 +
(after.tv_usec - before.tv_usec) / 100);
int newKbits = n * 8 / 1000;
// limit rate to between 10kbit/s and 40Mbit/s
if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
timeWaitedIn100us += newTimeWaited;
timedKbits += newKbits;
}
return n;
}
void FdInStream::startTiming()
{
timing = true;
// Carry over up to 1s worth of previous rate for smoothing.
if (timeWaitedIn100us > 10000) {
timedKbits = timedKbits * 10000 / timeWaitedIn100us;
timeWaitedIn100us = 10000;
}
}
void FdInStream::stopTiming()
{
timing = false;
if (timeWaitedIn100us < timedKbits/2)
timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
}
unsigned int FdInStream::kbitsPerSecond()
{
// The following calculation will overflow 32-bit arithmetic if we have
// received more than about 50Mbytes (400Mbits) since we started timing, so
// it should be OK for a single RFB update.
return timedKbits * 10000 / timeWaitedIn100us;
}

78
common/rdr/FdInStream.h Normal file
View File

@ -0,0 +1,78 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// FdInStream streams from a file descriptor.
//
#ifndef __RDR_FDINSTREAM_H__
#define __RDR_FDINSTREAM_H__
#include <rdr/InStream.h>
namespace rdr {
class FdInStreamBlockCallback {
public:
virtual void blockCallback() = 0;
virtual ~FdInStreamBlockCallback() {}
};
class FdInStream : public InStream {
public:
FdInStream(int fd, int timeoutms=-1, int bufSize=0,
bool closeWhenDone_=false);
FdInStream(int fd, FdInStreamBlockCallback* blockCallback, int bufSize=0);
virtual ~FdInStream();
void setTimeout(int timeoutms);
void setBlockCallback(FdInStreamBlockCallback* blockCallback);
int getFd() { return fd; }
int pos();
void readBytes(void* data, int length);
void startTiming();
void stopTiming();
unsigned int kbitsPerSecond();
unsigned int timeWaited() { return timeWaitedIn100us; }
protected:
int overrun(int itemSize, int nItems, bool wait);
private:
int readWithTimeoutOrCallback(void* buf, int len, bool wait=true);
int fd;
bool closeWhenDone;
int timeoutms;
FdInStreamBlockCallback* blockCallback;
bool timing;
unsigned int timeWaitedIn100us;
unsigned int timedKbits;
int bufSize;
int offset;
U8* start;
};
} // end of namespace rdr
#endif

213
common/rdr/FdOutStream.cxx Normal file
View File

@ -0,0 +1,213 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman for Cendio AB
* Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
#include <winsock2.h>
#undef errno
#define errno WSAGetLastError()
#include <os/winerrno.h>
#else
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#endif
/* Old systems have select() in sys/time.h */
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <rdr/FdOutStream.h>
#include <rdr/Exception.h>
#include <rfb/util.h>
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 16384 };
FdOutStream::FdOutStream(int fd_, bool blocking_, int timeoutms_, int bufSize_)
: fd(fd_), blocking(blocking_), timeoutms(timeoutms_),
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
{
ptr = start = sentUpTo = new U8[bufSize];
end = start + bufSize;
gettimeofday(&lastWrite, NULL);
}
FdOutStream::~FdOutStream()
{
try {
blocking = true;
flush();
} catch (Exception&) {
}
delete [] start;
}
void FdOutStream::setTimeout(int timeoutms_) {
timeoutms = timeoutms_;
}
void FdOutStream::setBlocking(bool blocking_) {
blocking = blocking_;
}
int FdOutStream::length()
{
return offset + ptr - sentUpTo;
}
int FdOutStream::bufferUsage()
{
return ptr - sentUpTo;
}
unsigned FdOutStream::getIdleTime()
{
return rfb::msSince(&lastWrite);
}
void FdOutStream::flush()
{
while (sentUpTo < ptr) {
int n = writeWithTimeout((const void*) sentUpTo,
ptr - sentUpTo,
blocking? timeoutms : 0);
// Timeout?
if (n == 0) {
// If non-blocking then we're done here
if (!blocking)
break;
throw TimedOut();
}
sentUpTo += n;
offset += n;
}
// Managed to flush everything?
if (sentUpTo == ptr)
ptr = sentUpTo = start;
}
int FdOutStream::overrun(int itemSize, int nItems)
{
if (itemSize > bufSize)
throw Exception("FdOutStream overrun: max itemSize exceeded");
// First try to get rid of the data we have
flush();
// Still not enough space?
if (itemSize > end - ptr) {
// Can we shuffle things around?
// (don't do this if it gains us less than 25%)
if ((sentUpTo - start > bufSize / 4) &&
(itemSize < bufSize - (ptr - sentUpTo))) {
memmove(start, sentUpTo, ptr - sentUpTo);
ptr = start + (ptr - sentUpTo);
sentUpTo = start;
} else {
// Have to get rid of more data, so turn off non-blocking
// for a bit...
bool realBlocking;
realBlocking = blocking;
blocking = true;
flush();
blocking = realBlocking;
}
}
// Can we fit all the items asked for?
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
//
// writeWithTimeout() writes up to the given length in bytes from the given
// buffer to the file descriptor. If there is a timeout set and that timeout
// expires, it throws a TimedOut exception. Otherwise it returns the number of
// bytes written. It never attempts to send() unless select() indicates that
// the fd is writable - this means it can be used on an fd which has been set
// non-blocking. It also has to cope with the annoying possibility of both
// select() and send() returning EINTR.
//
int FdOutStream::writeWithTimeout(const void* data, int length, int timeoutms)
{
int n;
do {
fd_set fds;
struct timeval tv;
struct timeval* tvp = &tv;
if (timeoutms != -1) {
tv.tv_sec = timeoutms / 1000;
tv.tv_usec = (timeoutms % 1000) * 1000;
} else {
tvp = NULL;
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
n = select(fd+1, 0, &fds, 0, tvp);
} while (n < 0 && errno == EINTR);
if (n < 0)
throw SystemException("select", errno);
if (n == 0)
return 0;
do {
// select only guarantees that you can write SO_SNDLOWAT without
// blocking, which is normally 1. Use MSG_DONTWAIT to avoid
// blocking, when possible.
#ifndef MSG_DONTWAIT
n = ::send(fd, (const char*)data, length, 0);
#else
n = ::send(fd, (const char*)data, length, MSG_DONTWAIT);
#endif
} while (n < 0 && (errno == EINTR));
if (n < 0)
throw SystemException("write", errno);
gettimeofday(&lastWrite, NULL);
return n;
}

66
common/rdr/FdOutStream.h Normal file
View File

@ -0,0 +1,66 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// FdOutStream streams to a file descriptor.
//
#ifndef __RDR_FDOUTSTREAM_H__
#define __RDR_FDOUTSTREAM_H__
#include <sys/time.h>
#include <rdr/OutStream.h>
namespace rdr {
class FdOutStream : public OutStream {
public:
FdOutStream(int fd, bool blocking=true, int timeoutms=-1, int bufSize=0);
virtual ~FdOutStream();
void setTimeout(int timeoutms);
void setBlocking(bool blocking);
int getFd() { return fd; }
void flush();
int length();
int bufferUsage();
unsigned getIdleTime();
private:
int overrun(int itemSize, int nItems);
int writeWithTimeout(const void* data, int length, int timeoutms);
int fd;
bool blocking;
int timeoutms;
int bufSize;
int offset;
U8* start;
U8* sentUpTo;
struct timeval lastWrite;
};
}
#endif

View File

@ -0,0 +1,87 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2013 D. R. Commander. All Rights Reserved.
* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <errno.h>
#include <rdr/Exception.h>
#include <rdr/FileInStream.h>
using namespace rdr;
FileInStream::FileInStream(const char *fileName)
{
file = fopen(fileName, "rb");
if (!file)
throw SystemException("fopen", errno);
ptr = end = b;
}
FileInStream::~FileInStream(void) {
if (file) {
fclose(file);
file = NULL;
}
}
void FileInStream::reset(void) {
if (!file)
throw Exception("File is not open");
if (fseek(file, 0, SEEK_SET) != 0)
throw SystemException("fseek", errno);
ptr = end = b;
}
int FileInStream::pos()
{
if (!file)
throw Exception("File is not open");
return ftell(file) + ptr - b;
}
int FileInStream::overrun(int itemSize, int nItems, bool wait)
{
if (itemSize > (int)sizeof(b))
throw Exception("FileInStream overrun: max itemSize exceeded");
if (end - ptr != 0)
memmove(b, ptr, end - ptr);
end -= ptr - b;
ptr = b;
while (end < b + itemSize) {
size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
if (n == 0) {
if (ferror(file))
throw SystemException("fread", errno);
if (feof(file))
throw EndOfStream();
return 0;
}
end += b + sizeof(b) - end;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}

50
common/rdr/FileInStream.h Normal file
View File

@ -0,0 +1,50 @@
/* Copyright (C) 2013 D. R. Commander. All Rights Reserved.
* Copyright 2015 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_FILEINSTREAM_H__
#define __RDR_FILEINSTREAM_H__
#include <stdio.h>
#include <rdr/InStream.h>
namespace rdr {
class FileInStream : public InStream {
public:
FileInStream(const char *fileName);
~FileInStream(void);
void reset(void);
int pos();
protected:
int overrun(int itemSize, int nItems, bool wait = true);
private:
U8 b[131072];
FILE *file;
};
} // end of namespace rdr
#endif

View File

@ -0,0 +1,52 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// A FixedMemOutStream writes to a buffer of a fixed length.
//
#ifndef __RDR_FIXEDMEMOUTSTREAM_H__
#define __RDR_FIXEDMEMOUTSTREAM_H__
#include <rdr/OutStream.h>
#include <rdr/Exception.h>
namespace rdr {
class FixedMemOutStream : public OutStream {
public:
FixedMemOutStream(void* buf, int len) {
ptr = start = (U8*)buf;
end = start + len;
}
int length() { return ptr - start; }
void reposition(int pos) { ptr = start + pos; }
const void* data() { return (const void*)start; }
private:
int overrun(int itemSize, int nItems) { throw EndOfStream(); }
U8* start;
};
}
#endif

117
common/rdr/HexInStream.cxx Normal file
View File

@ -0,0 +1,117 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/HexInStream.h>
#include <rdr/Exception.h>
#include <stdlib.h>
#include <ctype.h>
using namespace rdr;
const int DEFAULT_BUF_LEN = 16384;
static inline int min(int a, int b) {return a<b ? a : b;}
HexInStream::HexInStream(InStream& is, int bufSize_)
: bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_LEN), offset(0), in_stream(is)
{
ptr = end = start = new U8[bufSize];
}
HexInStream::~HexInStream() {
delete [] start;
}
bool HexInStream::readHexAndShift(char c, int* v) {
c=tolower(c);
if ((c >= '0') && (c <= '9'))
*v = (*v << 4) + (c - '0');
else if ((c >= 'a') && (c <= 'f'))
*v = (*v << 4) + (c - 'a' + 10);
else
return false;
return true;
}
bool HexInStream::hexStrToBin(const char* s, char** data, int* length) {
int l=strlen(s);
if ((l % 2) == 0) {
delete [] *data;
*data = 0; *length = 0;
if (l == 0)
return true;
*data = new char[l/2];
*length = l/2;
for(int i=0;i<l;i+=2) {
int byte = 0;
if (!readHexAndShift(s[i], &byte) ||
!readHexAndShift(s[i+1], &byte))
goto decodeError;
(*data)[i/2] = byte;
}
return true;
}
decodeError:
delete [] *data;
*data = 0;
*length = 0;
return false;
}
int HexInStream::pos() {
return offset + ptr - start;
}
int HexInStream::overrun(int itemSize, int nItems, bool wait) {
if (itemSize > bufSize)
throw Exception("HexInStream overrun: max itemSize exceeded");
if (end - ptr != 0)
memmove(start, ptr, end - ptr);
end -= ptr - start;
offset += ptr - start;
ptr = start;
while (end < ptr + itemSize) {
int n = in_stream.check(2, 1, wait);
if (n == 0) return 0;
const U8* iptr = in_stream.getptr();
const U8* eptr = in_stream.getend();
int length = min((eptr - iptr)/2, start + bufSize - end);
U8* optr = (U8*) end;
for (int i=0; i<length; i++) {
int v = 0;
readHexAndShift(iptr[i*2], &v);
readHexAndShift(iptr[i*2+1], &v);
optr[i] = v;
}
in_stream.setptr(iptr + length*2);
end += length;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}

50
common/rdr/HexInStream.h Normal file
View File

@ -0,0 +1,50 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_HEX_INSTREAM_H__
#define __RDR_HEX_INSTREAM_H__
#include <rdr/InStream.h>
namespace rdr {
class HexInStream : public InStream {
public:
HexInStream(InStream& is, int bufSize=0);
virtual ~HexInStream();
int pos();
static bool readHexAndShift(char c, int* v);
static bool hexStrToBin(const char* s, char** data, int* length);
protected:
int overrun(int itemSize, int nItems, bool wait);
private:
int bufSize;
U8* start;
int offset;
InStream& in_stream;
};
} // end of namespace rdr
#endif

110
common/rdr/HexOutStream.cxx Normal file
View File

@ -0,0 +1,110 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/HexOutStream.h>
#include <rdr/Exception.h>
using namespace rdr;
const int DEFAULT_BUF_LEN = 16384;
static inline int min(int a, int b) {return a<b ? a : b;}
HexOutStream::HexOutStream(OutStream& os, int buflen)
: out_stream(os), offset(0), bufSize(buflen ? buflen : DEFAULT_BUF_LEN)
{
if (bufSize % 2)
bufSize--;
ptr = start = new U8[bufSize];
end = start + bufSize;
}
HexOutStream::~HexOutStream() {
delete [] start;
}
char HexOutStream::intToHex(int i) {
if ((i>=0) && (i<=9))
return '0'+i;
else if ((i>=10) && (i<=15))
return 'a'+(i-10);
else
throw rdr::Exception("intToHex failed");
}
char* HexOutStream::binToHexStr(const char* data, int length) {
char* buffer = new char[length*2+1];
for (int i=0; i<length; i++) {
buffer[i*2] = intToHex((data[i] >> 4) & 15);
buffer[i*2+1] = intToHex((data[i] & 15));
if (!buffer[i*2] || !buffer[i*2+1]) {
delete [] buffer;
return 0;
}
}
buffer[length*2] = 0;
return buffer;
}
void
HexOutStream::writeBuffer() {
U8* pos = start;
while (pos != ptr) {
out_stream.check(2);
U8* optr = out_stream.getptr();
U8* oend = out_stream.getend();
int length = min(ptr-pos, (oend-optr)/2);
for (int i=0; i<length; i++) {
optr[i*2] = intToHex((pos[i] >> 4) & 0xf);
optr[i*2+1] = intToHex(pos[i] & 0xf);
}
out_stream.setptr(optr + length*2);
pos += length;
}
offset += ptr - start;
ptr = start;
}
int HexOutStream::length()
{
return offset + ptr - start;
}
void
HexOutStream::flush() {
writeBuffer();
out_stream.flush();
}
int
HexOutStream::overrun(int itemSize, int nItems) {
if (itemSize > bufSize)
throw Exception("HexOutStream overrun: max itemSize exceeded");
writeBuffer();
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}

51
common/rdr/HexOutStream.h Normal file
View File

@ -0,0 +1,51 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_HEX_OUTSTREAM_H__
#define __RDR_HEX_OUTSTREAM_H__
#include <rdr/OutStream.h>
namespace rdr {
class HexOutStream : public OutStream {
public:
HexOutStream(OutStream& os, int buflen=0);
virtual ~HexOutStream();
void flush();
int length();
static char intToHex(int i);
static char* binToHexStr(const char* data, int length);
private:
void writeBuffer();
int overrun(int itemSize, int nItems);
OutStream& out_stream;
U8* start;
int offset;
int bufSize;
};
}
#endif

35
common/rdr/InStream.cxx Normal file
View File

@ -0,0 +1,35 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/InStream.h>
#include <rdr/Exception.h>
using namespace rdr;
U32 InStream::maxStringLength = 65535;
char* InStream::readString()
{
U32 len = readU32();
if (len > maxStringLength)
throw Exception("InStream max string length exceeded");
char* str = new char[len+1];
readBytes(str, len);
str[len] = 0;
return str;
}

147
common/rdr/InStream.h Normal file
View File

@ -0,0 +1,147 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
// Representation).
//
#ifndef __RDR_INSTREAM_H__
#define __RDR_INSTREAM_H__
#include <rdr/types.h>
#include <string.h> // for memcpy
namespace rdr {
class InStream {
public:
virtual ~InStream() {}
// check() ensures there is buffer data for at least one item of size
// itemSize bytes. Returns the number of items in the buffer (up to a
// maximum of nItems). If wait is false, then instead of blocking to wait
// for the bytes, zero is returned if the bytes are not immediately
// available.
inline int check(int itemSize, int nItems=1, bool wait=true)
{
if (ptr + itemSize * nItems > end) {
if (ptr + itemSize > end)
return overrun(itemSize, nItems, wait);
nItems = (end - ptr) / itemSize;
}
return nItems;
}
// checkNoWait() tries to make sure that the given number of bytes can
// be read without blocking. It returns true if this is the case, false
// otherwise. The length must be "small" (less than the buffer size).
inline bool checkNoWait(int length) { return check(length, 1, false)!=0; }
// readU/SN() methods read unsigned and signed N-bit integers.
inline U8 readU8() { check(1); return *ptr++; }
inline U16 readU16() { check(2); int b0 = *ptr++; int b1 = *ptr++;
return b0 << 8 | b1; }
inline U32 readU32() { check(4); int b0 = *ptr++; int b1 = *ptr++;
int b2 = *ptr++; int b3 = *ptr++;
return b0 << 24 | b1 << 16 | b2 << 8 | b3; }
inline S8 readS8() { return (S8) readU8(); }
inline S16 readS16() { return (S16)readU16(); }
inline S32 readS32() { return (S32)readU32(); }
// readString() reads a string - a U32 length followed by the data.
// Returns a null-terminated string - the caller should delete[] it
// afterwards.
char* readString();
// maxStringLength protects against allocating a huge buffer. Set it
// higher if you need longer strings.
static U32 maxStringLength;
inline void skip(int bytes) {
while (bytes > 0) {
int n = check(1, bytes);
ptr += n;
bytes -= n;
}
}
// readBytes() reads an exact number of bytes.
void readBytes(void* data, int length) {
U8* dataPtr = (U8*)data;
U8* dataEnd = dataPtr + length;
while (dataPtr < dataEnd) {
int n = check(1, dataEnd - dataPtr);
memcpy(dataPtr, ptr, n);
ptr += n;
dataPtr += n;
}
}
// readOpaqueN() reads a quantity without byte-swapping.
inline U8 readOpaque8() { return readU8(); }
inline U16 readOpaque16() { check(2); U16 r; ((U8*)&r)[0] = *ptr++;
((U8*)&r)[1] = *ptr++; return r; }
inline U32 readOpaque32() { check(4); U32 r; ((U8*)&r)[0] = *ptr++;
((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++;
((U8*)&r)[3] = *ptr++; return r; }
// pos() returns the position in the stream.
virtual int pos() = 0;
// getptr(), getend() and setptr() are "dirty" methods which allow you to
// manipulate the buffer directly. This is useful for a stream which is a
// wrapper around an underlying stream.
inline const U8* getptr() const { return ptr; }
inline const U8* getend() const { return end; }
inline void setptr(const U8* p) { ptr = p; }
private:
// overrun() is implemented by a derived class to cope with buffer overrun.
// It ensures there are at least itemSize bytes of buffer data. Returns
// the number of items in the buffer (up to a maximum of nItems). itemSize
// is supposed to be "small" (a few bytes). If wait is false, then
// instead of blocking to wait for the bytes, zero is returned if the bytes
// are not immediately available.
virtual int overrun(int itemSize, int nItems, bool wait=true) = 0;
protected:
InStream() {}
const U8* ptr;
const U8* end;
};
}
#endif

63
common/rdr/MemInStream.h Normal file
View File

@ -0,0 +1,63 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// rdr::MemInStream is an InStream which streams from a given memory buffer.
// If the deleteWhenDone parameter is true then the buffer will be delete[]d in
// the destructor. Note that it is delete[]d as a U8* - strictly speaking this
// means it ought to be new[]ed as a U8* as well, but on most platforms this
// doesn't matter.
//
#ifndef __RDR_MEMINSTREAM_H__
#define __RDR_MEMINSTREAM_H__
#include <rdr/InStream.h>
#include <rdr/Exception.h>
namespace rdr {
class MemInStream : public InStream {
public:
MemInStream(const void* data, int len, bool deleteWhenDone_=false)
: start((const U8*)data), deleteWhenDone(deleteWhenDone_)
{
ptr = start;
end = start + len;
}
virtual ~MemInStream() {
if (deleteWhenDone)
delete [] start;
}
int pos() { return ptr - start; }
void reposition(int pos) { ptr = start + pos; }
private:
int overrun(int itemSize, int nItems, bool wait) { throw EndOfStream(); }
const U8* start;
bool deleteWhenDone;
};
}
#endif

83
common/rdr/MemOutStream.h Normal file
View File

@ -0,0 +1,83 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// A MemOutStream grows as needed when data is written to it.
//
#ifndef __RDR_MEMOUTSTREAM_H__
#define __RDR_MEMOUTSTREAM_H__
#include <rdr/OutStream.h>
namespace rdr {
class MemOutStream : public OutStream {
public:
MemOutStream(int len=1024) {
start = ptr = new U8[len];
end = start + len;
}
virtual ~MemOutStream() {
delete [] start;
}
void writeBytes(const void* data, int length) {
check(length);
memcpy(ptr, data, length);
ptr += length;
}
int length() { return ptr - start; }
void clear() { ptr = start; };
void clearAndZero() { memset(start, 0, ptr-start); clear(); }
void reposition(int pos) { ptr = start + pos; }
// data() returns a pointer to the buffer.
const void* data() { return (const void*)start; }
protected:
// overrun() either doubles the buffer or adds enough space for nItems of
// size itemSize bytes.
int overrun(int itemSize, int nItems) {
int len = ptr - start + itemSize * nItems;
if (len < (end - start) * 2)
len = (end - start) * 2;
U8* newStart = new U8[len];
memcpy(newStart, start, ptr - start);
ptr = newStart + (ptr - start);
delete [] start;
start = newStart;
end = newStart + len;
return nItems;
}
U8* start;
};
}
#endif

158
common/rdr/OutStream.h Normal file
View File

@ -0,0 +1,158 @@
/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// rdr::OutStream marshalls data into a buffer stored in RDR (RFB Data
// Representation).
//
#ifndef __RDR_OUTSTREAM_H__
#define __RDR_OUTSTREAM_H__
#include <rdr/types.h>
#include <rdr/InStream.h>
#include <string.h> // for memcpy
namespace rdr {
class OutStream {
protected:
OutStream() {}
public:
virtual ~OutStream() {}
// check() ensures there is buffer space for at least one item of size
// itemSize bytes. Returns the number of items which fit (up to a maximum
// of nItems).
inline int check(int itemSize, int nItems=1)
{
if (ptr + itemSize * nItems > end) {
if (ptr + itemSize > end)
return overrun(itemSize, nItems);
nItems = (end - ptr) / itemSize;
}
return nItems;
}
// writeU/SN() methods write unsigned and signed N-bit integers.
inline void writeU8( U8 u) { check(1); *ptr++ = u; }
inline void writeU16(U16 u) { check(2); *ptr++ = u >> 8; *ptr++ = (U8)u; }
inline void writeU32(U32 u) { check(4); *ptr++ = u >> 24; *ptr++ = u >> 16;
*ptr++ = u >> 8; *ptr++ = u; }
inline void writeS8( S8 s) { writeU8((U8)s); }
inline void writeS16(S16 s) { writeU16((U16)s); }
inline void writeS32(S32 s) { writeU32((U32)s); }
// writeString() writes a string - a U32 length followed by the data. The
// given string should be null-terminated (but the terminating null is not
// written to the stream).
inline void writeString(const char* str) {
U32 len = strlen(str);
writeU32(len);
writeBytes(str, len);
}
inline void pad(int bytes) {
while (bytes-- > 0) writeU8(0);
}
inline void skip(int bytes) {
while (bytes > 0) {
int n = check(1, bytes);
ptr += n;
bytes -= n;
}
}
// writeBytes() writes an exact number of bytes.
void writeBytes(const void* data, int length) {
const U8* dataPtr = (const U8*)data;
const U8* dataEnd = dataPtr + length;
while (dataPtr < dataEnd) {
int n = check(1, dataEnd - dataPtr);
memcpy(ptr, dataPtr, n);
ptr += n;
dataPtr += n;
}
}
// copyBytes() efficiently transfers data between streams
void copyBytes(InStream* is, int length) {
while (length > 0) {
int n = check(1, length);
is->readBytes(ptr, n);
ptr += n;
length -= n;
}
}
// writeOpaqueN() writes a quantity without byte-swapping.
inline void writeOpaque8( U8 u) { writeU8(u); }
inline void writeOpaque16(U16 u) { check(2); *ptr++ = ((U8*)&u)[0];
*ptr++ = ((U8*)&u)[1]; }
inline void writeOpaque32(U32 u) { check(4); *ptr++ = ((U8*)&u)[0];
*ptr++ = ((U8*)&u)[1];
*ptr++ = ((U8*)&u)[2];
*ptr++ = ((U8*)&u)[3]; }
// length() returns the length of the stream.
virtual int length() = 0;
// flush() requests that the stream be flushed.
virtual void flush() {}
// getptr(), getend() and setptr() are "dirty" methods which allow you to
// manipulate the buffer directly. This is useful for a stream which is a
// wrapper around an underlying stream.
inline U8* getptr() { return ptr; }
inline U8* getend() { return end; }
inline void setptr(U8* p) { ptr = p; }
private:
// overrun() is implemented by a derived class to cope with buffer overrun.
// It ensures there are at least itemSize bytes of buffer space. Returns
// the number of items which fit (up to a maximum of nItems). itemSize is
// supposed to be "small" (a few bytes).
virtual int overrun(int itemSize, int nItems) = 0;
protected:
U8* ptr;
U8* end;
};
}
#endif

130
common/rdr/RandomStream.cxx Normal file
View File

@ -0,0 +1,130 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/RandomStream.h>
#include <rdr/Exception.h>
#include <time.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#include <errno.h>
#else
#define getpid() GetCurrentProcessId()
#ifndef RFB_HAVE_WINCRYPT
#pragma message(" NOTE: Not building WinCrypt-based RandomStream")
#endif
#endif
using namespace rdr;
const int DEFAULT_BUF_LEN = 256;
unsigned int RandomStream::seed;
RandomStream::RandomStream()
: offset(0)
{
ptr = end = start = new U8[DEFAULT_BUF_LEN];
#ifdef RFB_HAVE_WINCRYPT
provider = 0;
if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) {
if (GetLastError() == (DWORD)NTE_BAD_KEYSET) {
if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
fprintf(stderr, "RandomStream: unable to create keyset\n");
provider = 0;
}
} else {
fprintf(stderr, "RandomStream: unable to acquire context\n");
provider = 0;
}
}
if (!provider) {
#else
#ifndef WIN32
fp = fopen("/dev/urandom", "r");
if (!fp)
fp = fopen("/dev/random", "r");
if (!fp) {
#else
{
#endif
#endif
fprintf(stderr,"RandomStream: warning: no OS supplied random source - using rand()\n");
seed += (unsigned int) time(0) + getpid() + getpid() * 987654 + rand();
srand(seed);
}
}
RandomStream::~RandomStream() {
delete [] start;
#ifdef RFB_HAVE_WINCRYPT
if (provider)
CryptReleaseContext(provider, 0);
#endif
#ifndef WIN32
if (fp) fclose(fp);
#endif
}
int RandomStream::pos() {
return offset + ptr - start;
}
int RandomStream::overrun(int itemSize, int nItems, bool wait) {
if (itemSize > DEFAULT_BUF_LEN)
throw Exception("RandomStream overrun: max itemSize exceeded");
if (end - ptr != 0)
memmove(start, ptr, end - ptr);
end -= ptr - start;
offset += ptr - start;
ptr = start;
int length = start + DEFAULT_BUF_LEN - end;
#ifdef RFB_HAVE_WINCRYPT
if (provider) {
if (!CryptGenRandom(provider, length, (U8*)end))
throw rdr::SystemException("unable to CryptGenRandom", GetLastError());
end += length;
} else {
#else
#ifndef WIN32
if (fp) {
int n = fread((U8*)end, length, 1, fp);
if (n != 1)
throw rdr::SystemException("reading /dev/urandom or /dev/random failed",
errno);
end += length;
} else {
#else
{
#endif
#endif
for (int i=0; i<length; i++)
*(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}

63
common/rdr/RandomStream.h Normal file
View File

@ -0,0 +1,63 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_RANDOMSTREAM_H__
#define __RDR_RANDOMSTREAM_H__
#include <stdio.h>
#include <rdr/InStream.h>
#ifdef WIN32
#include <windows.h>
#include <wincrypt.h>
#ifdef WINCRYPT32API
#define RFB_HAVE_WINCRYPT
#endif
#endif
namespace rdr {
class RandomStream : public InStream {
public:
RandomStream();
virtual ~RandomStream();
int pos();
protected:
int overrun(int itemSize, int nItems, bool wait);
private:
U8* start;
int offset;
static unsigned int seed;
#ifdef RFB_HAVE_WINCRYPT
HCRYPTPROV provider;
#endif
#ifndef WIN32
FILE* fp;
#endif
};
} // end of namespace rdr
#endif

View File

@ -0,0 +1,102 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_SUBSTITUTINGINSTREAM_H__
#define __RDR_SUBSTITUTINGINSTREAM_H__
#include <rdr/InStream.h>
#include <rdr/Exception.h>
namespace rdr {
class Substitutor {
public:
virtual char* substitute(const char* varName) = 0;
};
class SubstitutingInStream : public InStream {
public:
SubstitutingInStream(InStream* underlying_, Substitutor* s,
int maxVarNameLen_)
: underlying(underlying_), dollar(0), substitutor(s), subst(0),
maxVarNameLen(maxVarNameLen_)
{
ptr = end = underlying->getptr();
varName = new char[maxVarNameLen+1];
}
~SubstitutingInStream() {
delete underlying;
delete [] varName;
delete [] subst;
}
int pos() { return underlying->pos(); }
virtual int overrun(int itemSize, int nItems, bool wait=true) {
if (itemSize != 1)
throw new rdr::Exception("SubstitutingInStream: itemSize must be 1");
if (subst) {
delete [] subst;
subst = 0;
} else {
underlying->setptr(ptr);
}
underlying->check(1);
ptr = underlying->getptr();
end = underlying->getend();
dollar = (const U8*)memchr(ptr, '$', end-ptr);
if (dollar) {
if (dollar == ptr) {
try {
int i = 0;
while (i < maxVarNameLen) {
varName[i++] = underlying->readS8();
varName[i] = 0;
subst = substitutor->substitute(varName);
if (subst) {
ptr = (U8*)subst;
end = (U8*)subst + strlen(subst);
break;
}
}
} catch (EndOfStream&) {
}
if (!subst)
dollar = (const U8*)memchr(ptr+1, '$', end-ptr-1);
}
if (!subst && dollar) end = dollar;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
InStream* underlying;
const U8* dollar;
Substitutor* substitutor;
char* varName;
char* subst;
int maxVarNameLen;
};
}
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <rdr/TLSException.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
using namespace rdr;
#ifdef HAVE_GNUTLS
TLSException::TLSException(const char* s, int err_)
: Exception("%s: %s (%d)", s, gnutls_strerror(err_), err_), err(err_)
{
}
#endif /* HAVE_GNUTLS */

35
common/rdr/TLSException.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_TLSEXCEPTION_H__
#define __RDR_TLSEXCEPTION_H__
#include <rdr/Exception.h>
namespace rdr {
struct TLSException : public Exception {
int err;
TLSException(const char* s, int err_);
};
}
#endif

125
common/rdr/TLSInStream.cxx Normal file
View File

@ -0,0 +1,125 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <rdr/Exception.h>
#include <rdr/TLSException.h>
#include <rdr/TLSInStream.h>
#include <errno.h>
#ifdef HAVE_GNUTLS
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 16384 };
ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
{
TLSInStream* self= (TLSInStream*) str;
InStream *in = self->in;
try {
if (!in->check(1, 1, false)) {
gnutls_transport_set_errno(self->session, EAGAIN);
return -1;
}
if (in->getend() - in->getptr() < (ptrdiff_t)size)
size = in->getend() - in->getptr();
in->readBytes(data, size);
} catch (Exception& e) {
gnutls_transport_set_errno(self->session, EINVAL);
return -1;
}
return size;
}
TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session)
: session(_session), in(_in), bufSize(DEFAULT_BUF_SIZE), offset(0)
{
gnutls_transport_ptr_t recv, send;
ptr = end = start = new U8[bufSize];
gnutls_transport_set_pull_function(session, pull);
gnutls_transport_get_ptr2(session, &recv, &send);
gnutls_transport_set_ptr2(session, this, send);
}
TLSInStream::~TLSInStream()
{
gnutls_transport_set_pull_function(session, NULL);
delete[] start;
}
int TLSInStream::pos()
{
return offset + ptr - start;
}
int TLSInStream::overrun(int itemSize, int nItems, bool wait)
{
if (itemSize > bufSize)
throw Exception("TLSInStream overrun: max itemSize exceeded");
if (end - ptr != 0)
memmove(start, ptr, end - ptr);
offset += ptr - start;
end -= ptr - start;
ptr = start;
while (end < start + itemSize) {
int n = readTLS((U8*) end, start + bufSize - end, wait);
if (!wait && n == 0)
return 0;
end += n;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
int TLSInStream::readTLS(U8* buf, int len, bool wait)
{
int n;
n = in->check(1, 1, wait);
if (n == 0)
return 0;
n = gnutls_record_recv(session, (void *) buf, len);
if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
return 0;
if (n < 0) throw TLSException("readTLS", n);
return n;
}
#endif

55
common/rdr/TLSInStream.h Normal file
View File

@ -0,0 +1,55 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_TLSINSTREAM_H__
#define __RDR_TLSINSTREAM_H__
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#include <rdr/InStream.h>
namespace rdr {
class TLSInStream : public InStream {
public:
TLSInStream(InStream* in, gnutls_session_t session);
virtual ~TLSInStream();
int pos();
private:
int overrun(int itemSize, int nItems, bool wait);
int readTLS(U8* buf, int len, bool wait);
static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size);
gnutls_session_t session;
InStream* in;
int bufSize;
int offset;
U8* start;
};
};
#endif
#endif

123
common/rdr/TLSOutStream.cxx Normal file
View File

@ -0,0 +1,123 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <rdr/Exception.h>
#include <rdr/TLSException.h>
#include <rdr/TLSOutStream.h>
#include <errno.h>
#ifdef HAVE_GNUTLS
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 16384 };
ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data,
size_t size)
{
TLSOutStream* self= (TLSOutStream*) str;
OutStream *out = self->out;
try {
out->writeBytes(data, size);
out->flush();
} catch (Exception& e) {
gnutls_transport_set_errno(self->session, EINVAL);
return -1;
}
return size;
}
TLSOutStream::TLSOutStream(OutStream* _out, gnutls_session_t _session)
: session(_session), out(_out), bufSize(DEFAULT_BUF_SIZE), offset(0)
{
gnutls_transport_ptr_t recv, send;
ptr = start = new U8[bufSize];
end = start + bufSize;
gnutls_transport_set_push_function(session, push);
gnutls_transport_get_ptr2(session, &recv, &send);
gnutls_transport_set_ptr2(session, recv, this);
}
TLSOutStream::~TLSOutStream()
{
#if 0
try {
// flush();
} catch (Exception&) {
}
#endif
gnutls_transport_set_push_function(session, NULL);
delete [] start;
}
int TLSOutStream::length()
{
return offset + ptr - start;
}
void TLSOutStream::flush()
{
U8* sentUpTo = start;
while (sentUpTo < ptr) {
int n = writeTLS(sentUpTo, ptr - sentUpTo);
sentUpTo += n;
offset += n;
}
ptr = start;
out->flush();
}
int TLSOutStream::overrun(int itemSize, int nItems)
{
if (itemSize > bufSize)
throw Exception("TLSOutStream overrun: max itemSize exceeded");
flush();
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
int TLSOutStream::writeTLS(const U8* data, int length)
{
int n;
n = gnutls_record_send(session, data, length);
if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
return 0;
if (n < 0)
throw TLSException("writeTLS", n);
return n;
}
#endif

57
common/rdr/TLSOutStream.h Normal file
View File

@ -0,0 +1,57 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_TLSOUTSTREAM_H__
#define __RDR_TLSOUTSTREAM_H__
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#include <rdr/OutStream.h>
namespace rdr {
class TLSOutStream : public OutStream {
public:
TLSOutStream(OutStream* out, gnutls_session_t session);
virtual ~TLSOutStream();
void flush();
int length();
protected:
int overrun(int itemSize, int nItems);
private:
int writeTLS(const U8* data, int length);
static ssize_t push(gnutls_transport_ptr_t str, const void* data, size_t size);
gnutls_session_t session;
OutStream* out;
int bufSize;
U8* start;
int offset;
};
};
#endif
#endif

149
common/rdr/ZlibInStream.cxx Normal file
View File

@ -0,0 +1,149 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <assert.h>
#include <rdr/ZlibInStream.h>
#include <rdr/Exception.h>
#include <zlib.h>
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 16384 };
ZlibInStream::ZlibInStream(int bufSize_)
: underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0),
zs(NULL), bytesIn(0)
{
ptr = end = start = new U8[bufSize];
init();
}
ZlibInStream::~ZlibInStream()
{
deinit();
delete [] start;
}
void ZlibInStream::setUnderlying(InStream* is, int bytesIn_)
{
underlying = is;
bytesIn = bytesIn_;
ptr = end = start;
}
int ZlibInStream::pos()
{
return offset + ptr - start;
}
void ZlibInStream::removeUnderlying()
{
ptr = end = start;
if (!underlying) return;
while (bytesIn > 0) {
decompress(true);
end = start; // throw away any data
}
underlying = 0;
}
void ZlibInStream::reset()
{
deinit();
init();
}
void ZlibInStream::init()
{
assert(zs == NULL);
zs = new z_stream;
zs->zalloc = Z_NULL;
zs->zfree = Z_NULL;
zs->opaque = Z_NULL;
zs->next_in = Z_NULL;
zs->avail_in = 0;
if (inflateInit(zs) != Z_OK) {
delete zs;
zs = NULL;
throw Exception("ZlibInStream: inflateInit failed");
}
}
void ZlibInStream::deinit()
{
assert(zs != NULL);
removeUnderlying();
inflateEnd(zs);
delete zs;
zs = NULL;
}
int ZlibInStream::overrun(int itemSize, int nItems, bool wait)
{
if (itemSize > bufSize)
throw Exception("ZlibInStream overrun: max itemSize exceeded");
if (!underlying)
throw Exception("ZlibInStream overrun: no underlying stream");
if (end - ptr != 0)
memmove(start, ptr, end - ptr);
offset += ptr - start;
end -= ptr - start;
ptr = start;
while (end - ptr < itemSize) {
if (!decompress(wait))
return 0;
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
// decompress() calls the decompressor once. Note that this won't necessarily
// generate any output data - it may just consume some input data. Returns
// false if wait is false and we would block on the underlying stream.
bool ZlibInStream::decompress(bool wait)
{
zs->next_out = (U8*)end;
zs->avail_out = start + bufSize - end;
int n = underlying->check(1, 1, wait);
if (n == 0) return false;
zs->next_in = (U8*)underlying->getptr();
zs->avail_in = underlying->getend() - underlying->getptr();
if ((int)zs->avail_in > bytesIn)
zs->avail_in = bytesIn;
int rc = inflate(zs, Z_SYNC_FLUSH);
if (rc != Z_OK) {
throw Exception("ZlibInStream: inflate failed");
}
bytesIn -= zs->next_in - underlying->getptr();
end = zs->next_out;
underlying->setptr(zs->next_in);
return true;
}

63
common/rdr/ZlibInStream.h Normal file
View File

@ -0,0 +1,63 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// ZlibInStream streams from a compressed data stream ("underlying"),
// decompressing with zlib on the fly.
//
#ifndef __RDR_ZLIBINSTREAM_H__
#define __RDR_ZLIBINSTREAM_H__
#include <rdr/InStream.h>
struct z_stream_s;
namespace rdr {
class ZlibInStream : public InStream {
public:
ZlibInStream(int bufSize=0);
virtual ~ZlibInStream();
void setUnderlying(InStream* is, int bytesIn);
void removeUnderlying();
int pos();
void reset();
private:
void init();
void deinit();
int overrun(int itemSize, int nItems, bool wait);
bool decompress(bool wait);
InStream* underlying;
int bufSize;
int offset;
z_stream_s* zs;
int bytesIn;
U8* start;
};
} // end of namespace rdr
#endif

View File

@ -0,0 +1,201 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <stdio.h>
#include <rdr/ZlibOutStream.h>
#include <rdr/Exception.h>
#include <zlib.h>
#undef ZLIBOUT_DEBUG
using namespace rdr;
enum { DEFAULT_BUF_SIZE = 16384 };
ZlibOutStream::ZlibOutStream(OutStream* os, int bufSize_, int compressLevel)
: underlying(os), compressionLevel(compressLevel), newLevel(compressLevel),
bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
{
zs = new z_stream;
zs->zalloc = Z_NULL;
zs->zfree = Z_NULL;
zs->opaque = Z_NULL;
zs->next_in = Z_NULL;
zs->avail_in = 0;
if (deflateInit(zs, compressLevel) != Z_OK) {
delete zs;
throw Exception("ZlibOutStream: deflateInit failed");
}
ptr = start = new U8[bufSize];
end = start + bufSize;
}
ZlibOutStream::~ZlibOutStream()
{
try {
flush();
} catch (Exception&) {
}
delete [] start;
deflateEnd(zs);
delete zs;
}
void ZlibOutStream::setUnderlying(OutStream* os)
{
underlying = os;
}
void ZlibOutStream::setCompressionLevel(int level)
{
if (level < -1 || level > 9)
level = -1; // Z_DEFAULT_COMPRESSION
newLevel = level;
}
int ZlibOutStream::length()
{
return offset + ptr - start;
}
void ZlibOutStream::flush()
{
checkCompressionLevel();
zs->next_in = start;
zs->avail_in = ptr - start;
#ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos flush: avail_in %d\n",zs->avail_in);
#endif
// Force out everything from the zlib encoder
deflate(Z_SYNC_FLUSH);
offset += ptr - start;
ptr = start;
}
int ZlibOutStream::overrun(int itemSize, int nItems)
{
#ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos overrun\n");
#endif
if (itemSize > bufSize)
throw Exception("ZlibOutStream overrun: max itemSize exceeded");
checkCompressionLevel();
while (end - ptr < itemSize) {
zs->next_in = start;
zs->avail_in = ptr - start;
deflate(Z_NO_FLUSH);
// output buffer not full
if (zs->avail_in == 0) {
offset += ptr - start;
ptr = start;
} else {
// but didn't consume all the data? try shifting what's left to the
// start of the buffer.
fprintf(stderr,"z out buf not full, but in data not consumed\n");
memmove(start, zs->next_in, ptr - zs->next_in);
offset += zs->next_in - start;
ptr -= zs->next_in - start;
}
}
if (itemSize * nItems > end - ptr)
nItems = (end - ptr) / itemSize;
return nItems;
}
void ZlibOutStream::deflate(int flush)
{
int rc;
if (!underlying)
throw Exception("ZlibOutStream: underlying OutStream has not been set");
if ((flush == Z_NO_FLUSH) && (zs->avail_in == 0))
return;
do {
underlying->check(1);
zs->next_out = underlying->getptr();
zs->avail_out = underlying->getend() - underlying->getptr();
#ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos: calling deflate, avail_in %d, avail_out %d\n",
zs->avail_in,zs->avail_out);
#endif
rc = ::deflate(zs, flush);
if (rc != Z_OK) {
// Silly zlib returns an error if you try to flush something twice
if ((rc == Z_BUF_ERROR) && (flush != Z_NO_FLUSH))
break;
throw Exception("ZlibOutStream: deflate failed");
}
#ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos: after deflate: %d bytes\n",
zs->next_out-underlying->getptr());
#endif
underlying->setptr(zs->next_out);
} while (zs->avail_out == 0);
}
void ZlibOutStream::checkCompressionLevel()
{
int rc;
if (newLevel != compressionLevel) {
#ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos change: avail_in %d\n",zs->avail_in);
#endif
// zlib is just horribly stupid. It does an implicit flush on
// parameter changes, but the flush it does is not one that forces
// out all the data. And since you cannot flush things again, we
// cannot force out our data after the parameter change. Hence we
// need to do a more proper flush here first.
deflate(Z_SYNC_FLUSH);
rc = deflateParams (zs, newLevel, Z_DEFAULT_STRATEGY);
if (rc != Z_OK) {
// The implicit flush can result in this error, caused by the
// explicit flush we did above. It should be safe to ignore though
// as the first flush should have left things in a stable state...
if (rc != Z_BUF_ERROR)
throw Exception("ZlibOutStream: deflateParams failed");
}
compressionLevel = newLevel;
}
}

View File

@ -0,0 +1,63 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// ZlibOutStream streams to a compressed data stream (underlying), compressing
// with zlib on the fly.
//
#ifndef __RDR_ZLIBOUTSTREAM_H__
#define __RDR_ZLIBOUTSTREAM_H__
#include <rdr/OutStream.h>
struct z_stream_s;
namespace rdr {
class ZlibOutStream : public OutStream {
public:
ZlibOutStream(OutStream* os=0, int bufSize=0, int compressionLevel=-1);
virtual ~ZlibOutStream();
void setUnderlying(OutStream* os);
void setCompressionLevel(int level=-1);
void flush();
int length();
private:
int overrun(int itemSize, int nItems);
void deflate(int flush);
void checkCompressionLevel();
OutStream* underlying;
int compressionLevel;
int newLevel;
int bufSize;
int offset;
z_stream_s* zs;
U8* start;
};
} // end of namespace rdr
#endif

77
common/rdr/types.h Normal file
View File

@ -0,0 +1,77 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RDR_TYPES_H__
#define __RDR_TYPES_H__
namespace rdr {
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;
typedef unsigned long long U64;
typedef signed char S8;
typedef signed short S16;
typedef signed int S32;
class U8Array {
public:
U8Array() : buf(0) {}
U8Array(U8* a) : buf(a) {} // note: assumes ownership
U8Array(int len) : buf(new U8[len]) {}
~U8Array() { delete [] buf; }
// Get the buffer pointer & clear it (i.e. caller takes ownership)
U8* takeBuf() { U8* tmp = buf; buf = 0; return tmp; }
U8* buf;
};
class U16Array {
public:
U16Array() : buf(0) {}
U16Array(U16* a) : buf(a) {} // note: assumes ownership
U16Array(int len) : buf(new U16[len]) {}
~U16Array() { delete [] buf; }
U16* takeBuf() { U16* tmp = buf; buf = 0; return tmp; }
U16* buf;
};
class U32Array {
public:
U32Array() : buf(0) {}
U32Array(U32* a) : buf(a) {} // note: assumes ownership
U32Array(int len) : buf(new U32[len]) {}
~U32Array() { delete [] buf; }
U32* takeBuf() { U32* tmp = buf; buf = 0; return tmp; }
U32* buf;
};
class S32Array {
public:
S32Array() : buf(0) {}
S32Array(S32* a) : buf(a) {} // note: assumes ownership
S32Array(int len) : buf(new S32[len]) {}
~S32Array() { delete [] buf; }
S32* takeBuf() { S32* tmp = buf; buf = 0; return tmp; }
S32* buf;
};
} // end of namespace rdr
#endif

86
common/rfb/Blacklist.cxx Normal file
View File

@ -0,0 +1,86 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb/Blacklist.h>
#include <rfb/Configuration.h>
using namespace rfb;
IntParameter Blacklist::threshold("BlacklistThreshold",
"The number of unauthenticated connection attempts allowed from any "
"individual host before that host is black-listed",
5);
IntParameter Blacklist::initialTimeout("BlacklistTimeout",
"The initial timeout applied when a host is first black-listed. "
"The host cannot re-attempt a connection until the timeout expires.",
10);
Blacklist::Blacklist() {
}
Blacklist::~Blacklist() {
// Free the map keys
BlacklistMap::iterator i;
for (i=blm.begin(); i!=blm.end(); i++) {
strFree((char*)(*i).first);
}
}
bool Blacklist::isBlackmarked(const char* name) {
BlacklistMap::iterator i = blm.find(name);
if (i == blm.end()) {
// Entry is not already black-marked.
// Create the entry unmarked, unblocked,
// with suitable defaults set.
BlacklistInfo bi;
bi.marks = 1;
bi.blockUntil = 0;
bi.blockTimeout = initialTimeout;
blm[strDup(name)] = bi;
i = blm.find(name);
}
// Entry exists - has it reached the threshold yet?
if ((*i).second.marks >= threshold) {
// Yes - entry is blocked - has the timeout expired?
time_t now = time(0);
if (now >= (*i).second.blockUntil) {
// Timeout has expired. Reset timeout and allow
// a re-try.
(*i).second.blockUntil = now + (*i).second.blockTimeout;
(*i).second.blockTimeout = (*i).second.blockTimeout * 2;
return false;
}
// Blocked and timeout still in effect - reject!
return true;
}
// We haven't reached the threshold yet.
// Increment the black-mark counter but allow
// the entry to pass.
(*i).second.marks++;
return false;
}
void Blacklist::clearBlackmark(const char* name) {
BlacklistMap::iterator i = blm.find(name);
if (i != blm.end()) {
strFree((char*)(*i).first);
blm.erase(i);
}
}

91
common/rfb/Blacklist.h Normal file
View File

@ -0,0 +1,91 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// Blacklist.h - Handling of black-listed entities.
// Just keeps a table mapping strings to timing information, including
// how many times the entry has been black-listed and when to next
// put it on probation (e.g. allow a connection in from the host, and
// re-blacklist it if that fails).
//
#ifndef __RFB_BLACKLIST_H__
#define __RFB_BLACKLIST_H__
#include <string.h>
#include <time.h>
#include <map>
#include <rfb/Configuration.h>
#include <rfb/util.h>
namespace rfb {
//
// -=- Blacklist handler
//
// Parameters include a threshold after which to blacklist the named
// host, and a timeout after which to re-consider them.
//
// Threshold means that isBlackmarked can be called that number of times
// before it will return true.
//
// Timeout means that after that many seconds, the next call to isBlackmarked
// will return false. At the same time, the timeout is doubled, so that the
// next calls will fail, until the timeout expires again or clearBlackmark is
// called.
//
// When clearBlackMark is called, the corresponding entry is completely
// removed, causing the next isBlackmarked call to return false.
// KNOWN BUG: Client can keep making rejected requests, thus increasing
// their timeout. If client does this for 30 years, timeout may wrap round
// to a very small value again.
// THIS CLASS IS NOT THREAD-SAFE!
class Blacklist {
public:
Blacklist();
~Blacklist();
bool isBlackmarked(const char* name);
void clearBlackmark(const char* name);
static IntParameter threshold;
static IntParameter initialTimeout;
protected:
struct ltStr {
bool operator()(const char* s1, const char* s2) const {
return strcmp(s1, s2) < 0;
};
};
struct BlacklistInfo {
int marks;
time_t blockUntil;
unsigned int blockTimeout;
};
typedef std::map<const char*,BlacklistInfo,ltStr> BlacklistMap;
BlacklistMap blm;
};
}
#endif

366
common/rfb/CConnection.cxx Normal file
View File

@ -0,0 +1,366 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <stdio.h>
#include <string.h>
#include <rfb/Exception.h>
#include <rfb/fenceTypes.h>
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
#include <rfb/Security.h>
#include <rfb/SecurityClient.h>
#include <rfb/CConnection.h>
#include <rfb/util.h>
#include <rfb/LogWriter.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
using namespace rfb;
static LogWriter vlog("CConnection");
CConnection::CConnection()
: csecurity(0), is(0), os(0), reader_(0), writer_(0),
shared(false),
state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
framebuffer(NULL), decoder(this)
{
}
CConnection::~CConnection()
{
setFramebuffer(NULL);
if (csecurity) csecurity->destroy();
delete reader_;
reader_ = 0;
delete writer_;
writer_ = 0;
}
void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
{
is = is_;
os = os_;
}
void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
{
decoder.flush();
if ((framebuffer != NULL) && (fb != NULL)) {
Rect rect;
const rdr::U8* data;
int stride;
const rdr::U8 black[4] = { 0, 0, 0, 0 };
// Copy still valid area
rect.setXYWH(0, 0,
__rfbmin(fb->width(), framebuffer->width()),
__rfbmin(fb->height(), framebuffer->height()));
data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
fb->imageRect(rect, data, stride);
// Black out any new areas
if (fb->width() > framebuffer->width()) {
rect.setXYWH(framebuffer->width(), 0,
fb->width() - framebuffer->width(),
fb->height());
fb->fillRect(rect, black);
}
if (fb->height() > framebuffer->height()) {
rect.setXYWH(0, framebuffer->height(),
fb->width(),
fb->height() - framebuffer->height());
fb->fillRect(rect, black);
}
}
delete framebuffer;
framebuffer = fb;
}
void CConnection::initialiseProtocol()
{
state_ = RFBSTATE_PROTOCOL_VERSION;
}
void CConnection::processMsg()
{
switch (state_) {
case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
case RFBSTATE_SECURITY: processSecurityMsg(); break;
case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
case RFBSTATE_INITIALISATION: processInitMsg(); break;
case RFBSTATE_NORMAL: reader_->readMsg(); break;
case RFBSTATE_UNINITIALISED:
throw Exception("CConnection::processMsg: not initialised yet?");
default:
throw Exception("CConnection::processMsg: invalid state");
}
}
void CConnection::processVersionMsg()
{
vlog.debug("reading protocol version");
bool done;
if (!cp.readVersion(is, &done)) {
state_ = RFBSTATE_INVALID;
throw Exception("reading version failed: not an RFB server?");
}
if (!done) return;
vlog.info("Server supports RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
// The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
if (cp.beforeVersion(3,3)) {
vlog.error("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
state_ = RFBSTATE_INVALID;
throw Exception("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
} else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
cp.setVersion(3,3);
} else if (cp.afterVersion(3,8)) {
cp.setVersion(3,8);
}
cp.writeVersion(os);
state_ = RFBSTATE_SECURITY_TYPES;
vlog.info("Using RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
}
void CConnection::processSecurityTypesMsg()
{
vlog.debug("processing security types message");
int secType = secTypeInvalid;
std::list<rdr::U8> secTypes;
secTypes = security.GetEnabledSecTypes();
if (cp.isVersion(3,3)) {
// legacy 3.3 server may only offer "vnc authentication" or "none"
secType = is->readU32();
if (secType == secTypeInvalid) {
throwConnFailedException();
} else if (secType == secTypeNone || secType == secTypeVncAuth) {
std::list<rdr::U8>::iterator i;
for (i = secTypes.begin(); i != secTypes.end(); i++)
if (*i == secType) {
secType = *i;
break;
}
if (i == secTypes.end())
secType = secTypeInvalid;
} else {
vlog.error("Unknown 3.3 security type %d", secType);
throw Exception("Unknown 3.3 security type");
}
} else {
// >=3.7 server will offer us a list
int nServerSecTypes = is->readU8();
if (nServerSecTypes == 0)
throwConnFailedException();
std::list<rdr::U8>::iterator j;
for (int i = 0; i < nServerSecTypes; i++) {
rdr::U8 serverSecType = is->readU8();
vlog.debug("Server offers security type %s(%d)",
secTypeName(serverSecType), serverSecType);
/*
* Use the first type sent by server which matches client's type.
* It means server's order specifies priority.
*/
if (secType == secTypeInvalid) {
for (j = secTypes.begin(); j != secTypes.end(); j++)
if (*j == serverSecType) {
secType = *j;
break;
}
}
}
// Inform the server of our decision
if (secType != secTypeInvalid) {
os->writeU8(secType);
os->flush();
vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
}
}
if (secType == secTypeInvalid) {
state_ = RFBSTATE_INVALID;
vlog.error("No matching security types");
throw Exception("No matching security types");
}
state_ = RFBSTATE_SECURITY;
csecurity = security.GetCSecurity(secType);
processSecurityMsg();
}
void CConnection::processSecurityMsg()
{
vlog.debug("processing security message");
if (csecurity->processMsg(this)) {
state_ = RFBSTATE_SECURITY_RESULT;
processSecurityResultMsg();
}
}
void CConnection::processSecurityResultMsg()
{
vlog.debug("processing security result message");
int result;
if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
result = secResultOK;
} else {
if (!is->checkNoWait(1)) return;
result = is->readU32();
}
switch (result) {
case secResultOK:
securityCompleted();
return;
case secResultFailed:
vlog.debug("auth failed");
break;
case secResultTooMany:
vlog.debug("auth failed - too many tries");
break;
default:
throw Exception("Unknown security result from server");
}
state_ = RFBSTATE_INVALID;
if (cp.beforeVersion(3,8))
throw AuthFailureException();
CharArray reason(is->readString());
throw AuthFailureException(reason.buf);
}
void CConnection::processInitMsg()
{
vlog.debug("reading server initialisation");
reader_->readServerInit();
}
void CConnection::throwConnFailedException()
{
state_ = RFBSTATE_INVALID;
CharArray reason;
reason.buf = is->readString();
throw ConnFailedException(reason.buf);
}
void CConnection::securityCompleted()
{
state_ = RFBSTATE_INITIALISATION;
reader_ = new CMsgReader(this, is);
writer_ = new CMsgWriter(&cp, os);
vlog.debug("Authentication success!");
authSuccess();
writer_->writeClientInit(shared);
}
void CConnection::setDesktopSize(int w, int h)
{
decoder.flush();
CMsgHandler::setDesktopSize(w,h);
}
void CConnection::setExtendedDesktopSize(unsigned reason,
unsigned result,
int w, int h,
const ScreenSet& layout)
{
decoder.flush();
CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
}
void CConnection::readAndDecodeRect(const Rect& r, int encoding,
ModifiablePixelBuffer* pb)
{
decoder.decodeRect(r, encoding, pb);
decoder.flush();
}
void CConnection::framebufferUpdateStart()
{
CMsgHandler::framebufferUpdateStart();
}
void CConnection::framebufferUpdateEnd()
{
decoder.flush();
CMsgHandler::framebufferUpdateEnd();
}
void CConnection::dataRect(const Rect& r, int encoding)
{
decoder.decodeRect(r, encoding, framebuffer);
}
void CConnection::authSuccess()
{
}
void CConnection::serverInit()
{
state_ = RFBSTATE_NORMAL;
vlog.debug("initialisation done");
}
void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
{
CMsgHandler::fence(flags, len, data);
if (!(flags & fenceFlagRequest))
return;
// We cannot guarantee any synchronisation at this level
flags = 0;
writer()->writeFence(flags, len, data);
}

195
common/rfb/CConnection.h Normal file
View File

@ -0,0 +1,195 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CConnection - class on the client side representing a connection to a
// server. A derived class should override methods appropriately.
//
#ifndef __RFB_CCONNECTION_H__
#define __RFB_CCONNECTION_H__
#include <rfb/CMsgHandler.h>
#include <rfb/DecodeManager.h>
#include <rfb/SecurityClient.h>
#include <rfb/util.h>
namespace rfb {
class CMsgReader;
class CMsgWriter;
class CSecurity;
class IdentityVerifier;
class CConnection : public CMsgHandler {
public:
CConnection();
virtual ~CConnection();
// Methods to initialise the connection
// setServerName() is used to provide a unique(ish) name for the server to
// which we are connected. This might be the result of getPeerEndpoint on
// a TcpSocket, for example, or a host specified by DNS name & port.
// The serverName is used when verifying the Identity of a host (see RA2).
void setServerName(const char* name_) { serverName.replaceBuf(strDup(name_)); }
// setStreams() sets the streams to be used for the connection. These must
// be set before initialiseProtocol() and processMsg() are called. The
// CSecurity object may call setStreams() again to provide alternative
// streams over which the RFB protocol is sent (i.e. encrypting/decrypting
// streams). Ownership of the streams remains with the caller
// (i.e. SConnection will not delete them).
void setStreams(rdr::InStream* is, rdr::OutStream* os);
// setShared sets the value of the shared flag which will be sent to the
// server upon initialisation.
void setShared(bool s) { shared = s; }
// setProtocol3_3 configures whether or not the CConnection should
// only ever support protocol version 3.3
void setProtocol3_3(bool s) {useProtocol3_3 = s;}
// setFramebuffer configures the PixelBuffer that the CConnection
// should render all pixel data in to. Note that the CConnection
// takes ownership of the PixelBuffer and it must not be deleted by
// anyone else. Call setFramebuffer again with NULL or a different
// PixelBuffer to delete the previous one.
void setFramebuffer(ModifiablePixelBuffer* fb);
// initialiseProtocol() should be called once the streams and security
// types are set. Subsequently, processMsg() should be called whenever
// there is data to read on the InStream.
void initialiseProtocol();
// processMsg() should be called whenever there is either:
// - data available on the underlying network stream
// In this case, processMsg may return without processing an RFB message,
// if the available data does not result in an RFB message being ready
// to handle. e.g. if data is encrypted.
// NB: This makes it safe to call processMsg() in response to select()
// - data available on the CConnection's current InStream
// In this case, processMsg should always process the available RFB
// message before returning.
// NB: In either case, you must have called initialiseProtocol() first.
void processMsg();
// Methods overridden from CMsgHandler
// Note: These must be called by any deriving classes
virtual void setDesktopSize(int w, int h);
virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
int w, int h,
const ScreenSet& layout);
virtual void readAndDecodeRect(const Rect& r, int encoding,
ModifiablePixelBuffer* pb);
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
virtual void dataRect(const Rect& r, int encoding);
// Methods to be overridden in a derived class
// getIdVerifier() returns the identity verifier associated with the connection.
// Ownership of the IdentityVerifier is retained by the CConnection instance.
virtual IdentityVerifier* getIdentityVerifier() {return 0;}
// authSuccess() is called when authentication has succeeded.
virtual void authSuccess();
// serverInit() is called when the ServerInit message is received. The
// derived class must call on to CConnection::serverInit().
virtual void serverInit();
// Other methods
CMsgReader* reader() { return reader_; }
CMsgWriter* writer() { return writer_; }
rdr::InStream* getInStream() { return is; }
rdr::OutStream* getOutStream() { return os; }
// Access method used by SSecurity implementations that can verify servers'
// Identities, to determine the unique(ish) name of the server.
const char* getServerName() const { return serverName.buf; }
bool isSecure() const { return csecurity ? csecurity->isSecure() : false; }
enum stateEnum {
RFBSTATE_UNINITIALISED,
RFBSTATE_PROTOCOL_VERSION,
RFBSTATE_SECURITY_TYPES,
RFBSTATE_SECURITY,
RFBSTATE_SECURITY_RESULT,
RFBSTATE_INITIALISATION,
RFBSTATE_NORMAL,
RFBSTATE_INVALID
};
stateEnum state() { return state_; }
CSecurity *csecurity;
SecurityClient security;
protected:
void setState(stateEnum s) { state_ = s; }
void setReader(CMsgReader *r) { reader_ = r; }
void setWriter(CMsgWriter *w) { writer_ = w; }
ModifiablePixelBuffer* getFramebuffer() { return framebuffer; }
private:
// This is a default implementation of fences that automatically
// responds to requests, stating no support for synchronisation.
// When overriding, call CMsgHandler::fence() directly in order to
// state correct support for fence flags.
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
private:
void processVersionMsg();
void processSecurityTypesMsg();
void processSecurityMsg();
void processSecurityResultMsg();
void processInitMsg();
void throwAuthFailureException();
void throwConnFailedException();
void securityCompleted();
rdr::InStream* is;
rdr::OutStream* os;
CMsgReader* reader_;
CMsgWriter* writer_;
bool deleteStreamsWhenDone;
bool shared;
stateEnum state_;
CharArray serverName;
bool useProtocol3_3;
ModifiablePixelBuffer* framebuffer;
DecodeManager decoder;
};
}
#endif

105
common/rfb/CMakeLists.txt Normal file
View File

@ -0,0 +1,105 @@
include_directories(${CMAKE_SOURCE_DIR}/common ${JPEG_INCLUDE_DIR})
set(RFB_SOURCES
Blacklist.cxx
Congestion.cxx
CConnection.cxx
CMsgHandler.cxx
CMsgReader.cxx
CMsgWriter.cxx
CSecurityPlain.cxx
CSecurityStack.cxx
CSecurityVeNCrypt.cxx
CSecurityVncAuth.cxx
ComparingUpdateTracker.cxx
Configuration.cxx
ConnParams.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
Decoder.cxx
d3des.c
EncCache.cxx
EncodeManager.cxx
Encoder.cxx
HTTPServer.cxx
HextileDecoder.cxx
HextileEncoder.cxx
JpegCompressor.cxx
JpegDecompressor.cxx
KeyRemapper.cxx
LogWriter.cxx
Logger.cxx
Logger_file.cxx
Logger_stdio.cxx
Password.cxx
PixelBuffer.cxx
PixelFormat.cxx
RREEncoder.cxx
RREDecoder.cxx
RawDecoder.cxx
RawEncoder.cxx
Region.cxx
SConnection.cxx
SMsgHandler.cxx
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
Security.cxx
SecurityServer.cxx
SecurityClient.cxx
SSecurityPlain.cxx
SSecurityStack.cxx
SSecurityVncAuth.cxx
SSecurityVeNCrypt.cxx
ScaleFilters.cxx
Timer.cxx
TightDecoder.cxx
TightEncoder.cxx
TightJPEGEncoder.cxx
TightWEBPEncoder.cxx
UpdateTracker.cxx
VNCSConnectionST.cxx
VNCServerST.cxx
ZRLEEncoder.cxx
ZRLEDecoder.cxx
encodings.cxx
util.cxx
xxhash.c)
if(UNIX)
set(RFB_SOURCES ${RFB_SOURCES} Logger_syslog.cxx)
endif()
if(WIN32)
include_directories(${CMAKE_SOURCE_DIR}/win)
set(RFB_SOURCES ${RFB_SOURCES} WinPasswdValidator.cxx)
endif(WIN32)
set(RFB_LIBRARIES ${JPEG_LIBRARIES} os rdr Xregion)
if(HAVE_PAM)
set(RFB_SOURCES ${RFB_SOURCES} UnixPasswordValidator.cxx
UnixPasswordValidator.h pam.c pam.h)
set(RFB_LIBRARIES ${RFB_LIBRARIES} ${PAM_LIBS})
endif()
if(GNUTLS_FOUND)
set(RFB_SOURCES
${RFB_SOURCES}
CSecurityTLS.cxx
SSecurityTLS.cxx
)
set(RFB_LIBRARIES
${RFB_LIBRARIES}
${GNUTLS_LIBRARIES}
)
endif()
add_library(rfb STATIC ${RFB_SOURCES})
target_link_libraries(rfb ${RFB_LIBRARIES})
if(UNIX)
libtool_create_control_file(rfb)
endif()

View File

@ -0,0 +1,94 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <stdio.h>
#include <rfb/Exception.h>
#include <rfb/CMsgHandler.h>
#include <rfb/screenTypes.h>
using namespace rfb;
CMsgHandler::CMsgHandler()
{
}
CMsgHandler::~CMsgHandler()
{
}
void CMsgHandler::setDesktopSize(int width, int height)
{
cp.width = width;
cp.height = height;
}
void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result,
int width, int height,
const ScreenSet& layout)
{
cp.supportsSetDesktopSize = true;
if ((reason == reasonClient) && (result != resultSuccess))
return;
if (!layout.validate(width, height))
fprintf(stderr, "Server sent us an invalid screen layout\n");
cp.width = width;
cp.height = height;
cp.screenLayout = layout;
}
void CMsgHandler::setPixelFormat(const PixelFormat& pf)
{
cp.setPF(pf);
}
void CMsgHandler::setName(const char* name)
{
cp.setName(name);
}
void CMsgHandler::fence(rdr::U32 flags, unsigned len, const char data[])
{
cp.supportsFence = true;
}
void CMsgHandler::endOfContinuousUpdates()
{
cp.supportsContinuousUpdates = true;
}
void CMsgHandler::supportsQEMUKeyEvent()
{
cp.supportsQEMUKeyEvent = true;
}
void CMsgHandler::framebufferUpdateStart()
{
}
void CMsgHandler::framebufferUpdateEnd()
{
}
void CMsgHandler::setLEDState(unsigned int state)
{
cp.setLEDState(state);
}

78
common/rfb/CMsgHandler.h Normal file
View File

@ -0,0 +1,78 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CMsgHandler - class to handle incoming messages on the client side.
//
#ifndef __RFB_CMSGHANDLER_H__
#define __RFB_CMSGHANDLER_H__
#include <rdr/types.h>
#include <rfb/Pixel.h>
#include <rfb/ConnParams.h>
#include <rfb/Rect.h>
#include <rfb/ScreenSet.h>
namespace rdr { class InStream; }
namespace rfb {
class CMsgHandler {
public:
CMsgHandler();
virtual ~CMsgHandler();
// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat() and
// setName() methods, a derived class should call on to CMsgHandler's
// methods to set the members of cp appropriately.
virtual void setDesktopSize(int w, int h);
virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
int w, int h,
const ScreenSet& layout);
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data) = 0;
virtual void setPixelFormat(const PixelFormat& pf);
virtual void setName(const char* name);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
virtual void endOfContinuousUpdates();
virtual void supportsQEMUKeyEvent();
virtual void serverInit() = 0;
virtual void readAndDecodeRect(const Rect& r, int encoding,
ModifiablePixelBuffer* pb) = 0;
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
virtual void dataRect(const Rect& r, int encoding) = 0;
virtual void setColourMapEntries(int firstColour, int nColours,
rdr::U16* rgbs) = 0;
virtual void bell() = 0;
virtual void serverCutText(const char* str, rdr::U32 len) = 0;
virtual void setLEDState(unsigned int state);
ConnParams cp;
};
}
#endif

398
common/rfb/CMsgReader.cxx Normal file
View File

@ -0,0 +1,398 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <assert.h>
#include <stdio.h>
#include <rfb/msgTypes.h>
#include <rdr/InStream.h>
#include <rfb/Exception.h>
#include <rfb/util.h>
#include <rfb/CMsgHandler.h>
#include <rfb/CMsgReader.h>
using namespace rfb;
CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
: imageBufIdealSize(0), handler(handler_), is(is_),
nUpdateRectsLeft(0)
{
}
CMsgReader::~CMsgReader()
{
}
void CMsgReader::readServerInit()
{
int width = is->readU16();
int height = is->readU16();
handler->setDesktopSize(width, height);
PixelFormat pf;
pf.read(is);
handler->setPixelFormat(pf);
CharArray name(is->readString());
handler->setName(name.buf);
handler->serverInit();
}
void CMsgReader::readMsg()
{
if (nUpdateRectsLeft == 0) {
int type = is->readU8();
switch (type) {
case msgTypeSetColourMapEntries:
readSetColourMapEntries();
break;
case msgTypeBell:
readBell();
break;
case msgTypeServerCutText:
readServerCutText();
break;
case msgTypeFramebufferUpdate:
readFramebufferUpdate();
break;
case msgTypeServerFence:
readFence();
break;
case msgTypeEndOfContinuousUpdates:
readEndOfContinuousUpdates();
break;
default:
fprintf(stderr, "unknown message type %d\n", type);
throw Exception("unknown message type");
}
} else {
int x = is->readU16();
int y = is->readU16();
int w = is->readU16();
int h = is->readU16();
int encoding = is->readS32();
switch (encoding) {
case pseudoEncodingLastRect:
nUpdateRectsLeft = 1; // this rectangle is the last one
break;
case pseudoEncodingXCursor:
readSetXCursor(w, h, Point(x,y));
break;
case pseudoEncodingCursor:
readSetCursor(w, h, Point(x,y));
break;
case pseudoEncodingCursorWithAlpha:
readSetCursorWithAlpha(w, h, Point(x,y));
break;
case pseudoEncodingDesktopName:
readSetDesktopName(x, y, w, h);
break;
case pseudoEncodingDesktopSize:
handler->setDesktopSize(w, h);
break;
case pseudoEncodingExtendedDesktopSize:
readExtendedDesktopSize(x, y, w, h);
break;
case pseudoEncodingLEDState:
readLEDState();
case pseudoEncodingQEMUKeyEvent:
handler->supportsQEMUKeyEvent();
break;
default:
readRect(Rect(x, y, x+w, y+h), encoding);
break;
};
nUpdateRectsLeft--;
if (nUpdateRectsLeft == 0)
handler->framebufferUpdateEnd();
}
}
void CMsgReader::readSetColourMapEntries()
{
is->skip(1);
int firstColour = is->readU16();
int nColours = is->readU16();
rdr::U16Array rgbs(nColours * 3);
for (int i = 0; i < nColours * 3; i++)
rgbs.buf[i] = is->readU16();
handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
}
void CMsgReader::readBell()
{
handler->bell();
}
void CMsgReader::readServerCutText()
{
is->skip(3);
rdr::U32 len = is->readU32();
if (len > 256*1024) {
is->skip(len);
fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
return;
}
CharArray ca(len+1);
ca.buf[len] = 0;
is->readBytes(ca.buf, len);
handler->serverCutText(ca.buf, len);
}
void CMsgReader::readFence()
{
rdr::U32 flags;
rdr::U8 len;
char data[64];
is->skip(3);
flags = is->readU32();
len = is->readU8();
if (len > sizeof(data)) {
fprintf(stderr, "Ignoring fence with too large payload\n");
is->skip(len);
return;
}
is->readBytes(data, len);
handler->fence(flags, len, data);
}
void CMsgReader::readEndOfContinuousUpdates()
{
handler->endOfContinuousUpdates();
}
void CMsgReader::readFramebufferUpdate()
{
is->skip(1);
nUpdateRectsLeft = is->readU16();
handler->framebufferUpdateStart();
}
void CMsgReader::readRect(const Rect& r, int encoding)
{
if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
r.width(), r.height(), r.tl.x, r.tl.y,
handler->cp.width, handler->cp.height);
throw Exception("Rect too big");
}
if (r.is_empty())
fprintf(stderr, "Warning: zero size rect\n");
handler->dataRect(r, encoding);
}
void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw Exception("Too big cursor");
rdr::U8 buf[width*height*4];
if (width * height > 0) {
rdr::U8 pr, pg, pb;
rdr::U8 sr, sg, sb;
int data_len = ((width+7)/8) * height;
int mask_len = ((width+7)/8) * height;
rdr::U8Array data(data_len);
rdr::U8Array mask(mask_len);
int x, y;
rdr::U8* out;
pr = is->readU8();
pg = is->readU8();
pb = is->readU8();
sr = is->readU8();
sg = is->readU8();
sb = is->readU8();
is->readBytes(data.buf, data_len);
is->readBytes(mask.buf, mask_len);
int maskBytesPerRow = (width+7)/8;
out = buf;
for (y = 0;y < height;y++) {
for (x = 0;x < width;x++) {
int byte = y * maskBytesPerRow + x / 8;
int bit = 7 - x % 8;
if (data.buf[byte] & (1 << bit)) {
out[0] = pr;
out[1] = pg;
out[2] = pb;
} else {
out[0] = sr;
out[1] = sg;
out[2] = sb;
}
if (mask.buf[byte] & (1 << bit))
out[3] = 255;
else
out[3] = 0;
out += 4;
}
}
}
handler->setCursor(width, height, hotspot, buf);
}
void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw Exception("Too big cursor");
int data_len = width * height * (handler->cp.pf().bpp/8);
int mask_len = ((width+7)/8) * height;
rdr::U8Array data(data_len);
rdr::U8Array mask(mask_len);
int x, y;
rdr::U8 buf[width*height*4];
rdr::U8* in;
rdr::U8* out;
is->readBytes(data.buf, data_len);
is->readBytes(mask.buf, mask_len);
int maskBytesPerRow = (width+7)/8;
in = data.buf;
out = buf;
for (y = 0;y < height;y++) {
for (x = 0;x < width;x++) {
int byte = y * maskBytesPerRow + x / 8;
int bit = 7 - x % 8;
handler->cp.pf().rgbFromBuffer(out, in, 1);
if (mask.buf[byte] & (1 << bit))
out[3] = 255;
else
out[3] = 0;
in += handler->cp.pf().bpp/8;
out += 4;
}
}
handler->setCursor(width, height, hotspot, buf);
}
void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw Exception("Too big cursor");
int encoding;
const PixelFormat rgbaPF(32, 32, false, true, 255, 255, 255, 16, 8, 0);
ManagedPixelBuffer pb(rgbaPF, width, height);
PixelFormat origPF;
rdr::U8* buf;
int stride;
encoding = is->readS32();
origPF = handler->cp.pf();
handler->cp.setPF(rgbaPF);
handler->readAndDecodeRect(pb.getRect(), encoding, &pb);
handler->cp.setPF(origPF);
// On-wire data has pre-multiplied alpha, but we store it
// non-pre-multiplied
buf = pb.getBufferRW(pb.getRect(), &stride);
assert(stride == width);
for (int i = 0;i < pb.area();i++) {
rdr::U8 alpha;
alpha = buf[3];
if (alpha == 0)
alpha = 1; // Avoid division by zero
buf[0] = (unsigned)buf[0] * 255/alpha;
buf[1] = (unsigned)buf[1] * 255/alpha;
buf[2] = (unsigned)buf[2] * 255/alpha;
buf += 4;
}
pb.commitBufferRW(pb.getRect());
handler->setCursor(width, height, hotspot,
pb.getBuffer(pb.getRect(), &stride));
}
void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
{
char* name = is->readString();
if (x || y || w || h) {
fprintf(stderr, "Ignoring DesktopName rect with non-zero position/size\n");
} else {
handler->setName(name);
}
delete [] name;
}
void CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h)
{
unsigned int screens, i;
rdr::U32 id, flags;
int sx, sy, sw, sh;
ScreenSet layout;
screens = is->readU8();
is->skip(3);
for (i = 0;i < screens;i++) {
id = is->readU32();
sx = is->readU16();
sy = is->readU16();
sw = is->readU16();
sh = is->readU16();
flags = is->readU32();
layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
}
handler->setExtendedDesktopSize(x, y, w, h, layout);
}
void CMsgReader::readLEDState()
{
rdr::U8 state;
state = is->readU8();
handler->setLEDState(state);
}

77
common/rfb/CMsgReader.h Normal file
View File

@ -0,0 +1,77 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CMsgReader - class for reading RFB messages on the server side
// (i.e. messages from client to server).
//
#ifndef __RFB_CMSGREADER_H__
#define __RFB_CMSGREADER_H__
#include <rdr/types.h>
#include <rfb/Rect.h>
#include <rfb/encodings.h>
namespace rdr { class InStream; }
namespace rfb {
class CMsgHandler;
struct Rect;
class CMsgReader {
public:
CMsgReader(CMsgHandler* handler, rdr::InStream* is);
virtual ~CMsgReader();
void readServerInit();
// readMsg() reads a message, calling the handler as appropriate.
void readMsg();
rdr::InStream* getInStream() { return is; }
int imageBufIdealSize;
protected:
void readSetColourMapEntries();
void readBell();
void readServerCutText();
void readFence();
void readEndOfContinuousUpdates();
void readFramebufferUpdate();
void readRect(const Rect& r, int encoding);
void readSetXCursor(int width, int height, const Point& hotspot);
void readSetCursor(int width, int height, const Point& hotspot);
void readSetCursorWithAlpha(int width, int height, const Point& hotspot);
void readSetDesktopName(int x, int y, int w, int h);
void readExtendedDesktopSize(int x, int y, int w, int h);
void readLEDState();
CMsgHandler* handler;
rdr::InStream* is;
int nUpdateRectsLeft;
static const int maxCursorSize = 256;
};
}
#endif

276
common/rfb/CMsgWriter.cxx Normal file
View File

@ -0,0 +1,276 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <stdio.h>
#include <rdr/OutStream.h>
#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/encodings.h>
#include <rfb/qemuTypes.h>
#include <rfb/Exception.h>
#include <rfb/PixelFormat.h>
#include <rfb/Rect.h>
#include <rfb/ConnParams.h>
#include <rfb/Decoder.h>
#include <rfb/CMsgWriter.h>
using namespace rfb;
CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
: cp(cp_), os(os_)
{
}
CMsgWriter::~CMsgWriter()
{
}
void CMsgWriter::writeClientInit(bool shared)
{
os->writeU8(shared);
endMsg();
}
void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
{
startMsg(msgTypeSetPixelFormat);
os->pad(3);
pf.write(os);
endMsg();
}
void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
{
startMsg(msgTypeSetEncodings);
os->skip(1);
os->writeU16(nEncodings);
for (int i = 0; i < nEncodings; i++)
os->writeU32(encodings[i]);
endMsg();
}
// Ask for encodings based on which decoders are supported. Assumes higher
// encoding numbers are more desirable.
void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
{
int nEncodings = 0;
rdr::U32 encodings[encodingMax+3];
if (cp->supportsLocalCursor) {
encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
encodings[nEncodings++] = pseudoEncodingCursor;
encodings[nEncodings++] = pseudoEncodingXCursor;
}
if (cp->supportsDesktopResize)
encodings[nEncodings++] = pseudoEncodingDesktopSize;
if (cp->supportsExtendedDesktopSize)
encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
if (cp->supportsDesktopRename)
encodings[nEncodings++] = pseudoEncodingDesktopName;
if (cp->supportsLEDState)
encodings[nEncodings++] = pseudoEncodingLEDState;
encodings[nEncodings++] = pseudoEncodingLastRect;
encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
encodings[nEncodings++] = pseudoEncodingFence;
encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent;
if (Decoder::supported(preferredEncoding)) {
encodings[nEncodings++] = preferredEncoding;
}
if (useCopyRect) {
encodings[nEncodings++] = encodingCopyRect;
}
/*
* Prefer encodings in this order:
*
* Tight, ZRLE, Hextile, *
*/
if ((preferredEncoding != encodingTight) &&
Decoder::supported(encodingTight))
encodings[nEncodings++] = encodingTight;
if ((preferredEncoding != encodingZRLE) &&
Decoder::supported(encodingZRLE))
encodings[nEncodings++] = encodingZRLE;
if ((preferredEncoding != encodingHextile) &&
Decoder::supported(encodingHextile))
encodings[nEncodings++] = encodingHextile;
// Remaining encodings
for (int i = encodingMax; i >= 0; i--) {
switch (i) {
case encodingCopyRect:
case encodingTight:
case encodingZRLE:
case encodingHextile:
/* These have already been sent earlier */
break;
default:
if ((i != preferredEncoding) && Decoder::supported(i))
encodings[nEncodings++] = i;
}
}
if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
writeSetEncodings(nEncodings, encodings);
}
void CMsgWriter::writeSetDesktopSize(int width, int height,
const ScreenSet& layout)
{
if (!cp->supportsSetDesktopSize)
throw Exception("Server does not support SetDesktopSize");
startMsg(msgTypeSetDesktopSize);
os->pad(1);
os->writeU16(width);
os->writeU16(height);
os->writeU8(layout.num_screens());
os->pad(1);
ScreenSet::const_iterator iter;
for (iter = layout.begin();iter != layout.end();++iter) {
os->writeU32(iter->id);
os->writeU16(iter->dimensions.tl.x);
os->writeU16(iter->dimensions.tl.y);
os->writeU16(iter->dimensions.width());
os->writeU16(iter->dimensions.height());
os->writeU32(iter->flags);
}
endMsg();
}
void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
{
startMsg(msgTypeFramebufferUpdateRequest);
os->writeU8(incremental);
os->writeU16(r.tl.x);
os->writeU16(r.tl.y);
os->writeU16(r.width());
os->writeU16(r.height());
endMsg();
}
void CMsgWriter::writeEnableContinuousUpdates(bool enable,
int x, int y, int w, int h)
{
if (!cp->supportsContinuousUpdates)
throw Exception("Server does not support continuous updates");
startMsg(msgTypeEnableContinuousUpdates);
os->writeU8(!!enable);
os->writeU16(x);
os->writeU16(y);
os->writeU16(w);
os->writeU16(h);
endMsg();
}
void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
{
if (!cp->supportsFence)
throw Exception("Server does not support fences");
if (len > 64)
throw Exception("Too large fence payload");
if ((flags & ~fenceFlagsSupported) != 0)
throw Exception("Unknown fence flags");
startMsg(msgTypeClientFence);
os->pad(3);
os->writeU32(flags);
os->writeU8(len);
os->writeBytes(data, len);
endMsg();
}
void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
{
if (!cp->supportsQEMUKeyEvent || !keycode) {
/* This event isn't meaningful without a valid keysym */
if (!keysym)
return;
startMsg(msgTypeKeyEvent);
os->writeU8(down);
os->pad(2);
os->writeU32(keysym);
endMsg();
} else {
startMsg(msgTypeQEMUClientMessage);
os->writeU8(qemuExtendedKeyEvent);
os->writeU16(down);
os->writeU32(keysym);
os->writeU32(keycode);
endMsg();
}
}
void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
{
Point p(pos);
if (p.x < 0) p.x = 0;
if (p.y < 0) p.y = 0;
if (p.x >= cp->width) p.x = cp->width - 1;
if (p.y >= cp->height) p.y = cp->height - 1;
startMsg(msgTypePointerEvent);
os->writeU8(buttonMask);
os->writeU16(p.x);
os->writeU16(p.y);
endMsg();
}
void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len)
{
startMsg(msgTypeClientCutText);
os->pad(3);
os->writeU32(len);
os->writeBytes(str, len);
endMsg();
}
void CMsgWriter::startMsg(int type)
{
os->writeU8(type);
}
void CMsgWriter::endMsg()
{
os->flush();
}

67
common/rfb/CMsgWriter.h Normal file
View File

@ -0,0 +1,67 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CMsgWriter - class for writing RFB messages on the server side.
//
#ifndef __RFB_CMSGWRITER_H__
#define __RFB_CMSGWRITER_H__
#include <rdr/types.h>
namespace rdr { class OutStream; }
namespace rfb {
class PixelFormat;
class ConnParams;
struct ScreenSet;
struct Point;
struct Rect;
class CMsgWriter {
public:
CMsgWriter(ConnParams* cp, rdr::OutStream* os);
virtual ~CMsgWriter();
void writeClientInit(bool shared);
void writeSetPixelFormat(const PixelFormat& pf);
void writeSetEncodings(int nEncodings, rdr::U32* encodings);
void writeSetEncodings(int preferredEncoding, bool useCopyRect);
void writeSetDesktopSize(int width, int height, const ScreenSet& layout);
void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h);
void writeFence(rdr::U32 flags, unsigned len, const char data[]);
void writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
void writePointerEvent(const Point& pos, int buttonMask);
void writeClientCutText(const char* str, rdr::U32 len);
protected:
void startMsg(int type);
void endMsg();
ConnParams* cp;
rdr::OutStream* os;
};
}
#endif

61
common/rfb/CSecurity.h Normal file
View File

@ -0,0 +1,61 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CSecurity - class on the client side for handling security handshaking. A
// derived class for a particular security type overrides the processMsg()
// method.
// processMsg() is called first when the security type has been decided on, and
// will keep being called whenever there is data to read from the server. It
// should return false when it needs more data, or true when the security
// handshaking is over and we are now waiting for the SecurityResult message
// from the server. In the event of failure a suitable exception should be
// thrown.
//
// Note that the first time processMsg() is called, there is no guarantee that
// there is any data to read from the CConnection's InStream, but subsequent
// calls guarantee there is at least one byte which can be read without
// blocking.
//
// description is a string describing the level of encryption applied to the
// session, or null if no encryption will be used.
#ifndef __RFB_CSECURITY_H__
#define __RFB_CSECURITY_H__
#include <rfb/UserPasswdGetter.h>
namespace rfb {
class CConnection;
class CSecurity {
public:
virtual ~CSecurity() {}
virtual bool processMsg(CConnection* cc)=0;
virtual void destroy() { delete this; }
virtual int getType() const = 0;
virtual const char* description() const = 0;
virtual bool isSecure() const { return false; }
/*
* Use variable directly instead of dumb get/set methods.
* It MUST be set by viewer.
*/
static UserPasswdGetter *upg;
};
}
#endif

View File

@ -0,0 +1,37 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CSecurityNone.h
//
#ifndef __CSECURITYNONE_H__
#define __CSECURITYNONE_H__
#include <rfb/Security.h>
#include <rfb/CSecurity.h>
namespace rfb {
class CSecurityNone : public CSecurity {
public:
virtual bool processMsg(CConnection* cc) { return true; }
virtual int getType() const {return secTypeNone;}
virtual const char* description() const {return "No Encryption";}
};
}
#endif

View File

@ -0,0 +1,45 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb/CConnection.h>
#include <rfb/CSecurityPlain.h>
#include <rfb/UserPasswdGetter.h>
#include <rfb/util.h>
#include <rdr/OutStream.h>
using namespace rfb;
bool CSecurityPlain::processMsg(CConnection* cc)
{
rdr::OutStream* os = cc->getOutStream();
CharArray username;
CharArray password;
(CSecurity::upg)->getUserPasswd(cc->isSecure(), &username.buf, &password.buf);
// Return the response to the server
os->writeU32(strlen(username.buf));
os->writeU32(strlen(password.buf));
os->writeBytes(username.buf,strlen(username.buf));
os->writeBytes(password.buf,strlen(password.buf));
os->flush();
return true;
}

View File

@ -0,0 +1,35 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_CSECURITYPLAIN_H__
#define __RFB_CSECURITYPLAIN_H__
#include <rfb/CSecurity.h>
#include <rfb/Security.h>
namespace rfb {
class CSecurityPlain : public CSecurity {
public:
CSecurityPlain() {}
virtual bool processMsg(CConnection* cc);
virtual int getType() const { return secTypePlain; }
virtual const char* description() const { return "ask for username and password"; }
};
}
#endif

View File

@ -0,0 +1,74 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rfb/CSecurityStack.h>
using namespace rfb;
CSecurityStack::CSecurityStack(int Type, const char*Name, CSecurity* s0,
CSecurity* s1)
:name(Name),type(Type)
{
state = 0;
state0 = s0;
state1 = s1;
}
CSecurityStack::~CSecurityStack()
{
if (state0)
delete state0;
if (state1)
delete state1;
}
bool CSecurityStack::processMsg(CConnection* cc)
{
bool res=true;
if (state == 0) {
if (state0)
res = state0->processMsg(cc);
if (!res)
return res;
state++;
}
if (state == 1) {
if(state1)
res = state1->processMsg(cc);
if(!res)
return res;
state++;
}
return res;
}
bool CSecurityStack::isSecure() const
{
if (state0 && state0->isSecure())
return true;
if (state == 1 && state1 && state1->isSecure())
return true;
return false;
}

View File

@ -0,0 +1,44 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2006 OCCAM Financial Technology
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_CSECURITYSTACK_H__
#define __RFB_CSECURITYSTACK_H__
#include <rfb/CSecurity.h>
#include <rfb/Security.h>
namespace rfb {
class CSecurityStack : public CSecurity {
public:
CSecurityStack(int Type, const char *Name, CSecurity* s0 = 0, CSecurity* s1 = 0);
~CSecurityStack();
virtual bool processMsg(CConnection* cc);
virtual int getType() const {return type;};
virtual const char* description() const {return name;}
virtual bool isSecure() const;
protected:
int state;
CSecurity* state0;
CSecurity* state1;
const char* name;
int type;
};
}
#endif

445
common/rfb/CSecurityTLS.cxx Normal file
View File

@ -0,0 +1,445 @@
/*
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
* Copyright (C) 2010 m-privacy GmbH
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef HAVE_GNUTLS
#error "This header should not be compiled without HAVE_GNUTLS defined"
#endif
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <rfb/CSecurityTLS.h>
#include <rfb/SSecurityVeNCrypt.h>
#include <rfb/CConnection.h>
#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
#include <rfb/UserMsgBox.h>
#include <rdr/TLSInStream.h>
#include <rdr/TLSOutStream.h>
#include <os/os.h>
#include <gnutls/x509.h>
/*
* GNUTLS 2.6.5 and older didn't have some variables defined so don't use them.
* GNUTLS 1.X.X defined LIBGNUTLS_VERSION_NUMBER so treat it as "old" gnutls as
* well
*/
#if (defined(GNUTLS_VERSION_NUMBER) && GNUTLS_VERSION_NUMBER < 0x020606) || \
defined(LIBGNUTLS_VERSION_NUMBER)
#define WITHOUT_X509_TIMES
#endif
/* Ancient GNUTLS... */
#if !defined(GNUTLS_VERSION_NUMBER) && !defined(LIBGNUTLS_VERSION_NUMBER)
#define WITHOUT_X509_TIMES
#endif
using namespace rfb;
StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", "", ConfViewer);
StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", "", ConfViewer);
static LogWriter vlog("TLS");
CSecurityTLS::CSecurityTLS(bool _anon) : session(0), anon_cred(0),
anon(_anon), fis(0), fos(0)
{
cafile = X509CA.getData();
crlfile = X509CRL.getData();
if (gnutls_global_init() != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_global_init failed");
}
void CSecurityTLS::setDefaults()
{
char* homeDir = NULL;
if (getvnchomedir(&homeDir) == -1) {
vlog.error("Could not obtain VNC home directory path");
return;
}
int len = strlen(homeDir) + 1;
CharArray caDefault(len + 11);
CharArray crlDefault(len + 12);
sprintf(caDefault.buf, "%sx509_ca.pem", homeDir);
sprintf(crlDefault.buf, "%s509_crl.pem", homeDir);
delete [] homeDir;
if (!fileexists(caDefault.buf))
X509CA.setDefaultStr(strdup(caDefault.buf));
if (!fileexists(crlDefault.buf))
X509CRL.setDefaultStr(strdup(crlDefault.buf));
}
void CSecurityTLS::shutdown(bool needbye)
{
if (session && needbye)
if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != GNUTLS_E_SUCCESS)
vlog.error("gnutls_bye failed");
if (anon_cred) {
gnutls_anon_free_client_credentials(anon_cred);
anon_cred = 0;
}
if (cert_cred) {
gnutls_certificate_free_credentials(cert_cred);
cert_cred = 0;
}
if (session) {
gnutls_deinit(session);
session = 0;
}
}
CSecurityTLS::~CSecurityTLS()
{
shutdown(true);
if (fis)
delete fis;
if (fos)
delete fos;
delete[] cafile;
delete[] crlfile;
gnutls_global_deinit();
}
bool CSecurityTLS::processMsg(CConnection* cc)
{
rdr::InStream* is = cc->getInStream();
rdr::OutStream* os = cc->getOutStream();
client = cc;
if (!session) {
if (!is->checkNoWait(1))
return false;
if (is->readU8() == 0) {
rdr::U32 result = is->readU32();
CharArray reason;
if (result == secResultFailed || result == secResultTooMany)
reason.buf = is->readString();
else
reason.buf = strDup("protocol error");
throw AuthFailureException(reason.buf);
}
if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_init failed");
if (gnutls_set_default_priority(session) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_set_default_priority failed");
setParam();
}
rdr::TLSInStream *tlsis = new rdr::TLSInStream(is, session);
rdr::TLSOutStream *tlsos = new rdr::TLSOutStream(os, session);
int err;
err = gnutls_handshake(session);
if (err != GNUTLS_E_SUCCESS) {
delete tlsis;
delete tlsos;
if (!gnutls_error_is_fatal(err))
return false;
vlog.error("TLS Handshake failed: %s\n", gnutls_strerror (err));
shutdown(false);
throw AuthFailureException("TLS Handshake failed");
}
checkSession();
cc->setStreams(fis = tlsis, fos = tlsos);
return true;
}
void CSecurityTLS::setParam()
{
static const char kx_anon_priority[] = ":+ANON-ECDH:+ANON-DH";
int ret;
char *prio;
const char *err;
prio = (char*)malloc(strlen(Security::GnuTLSPriority) +
strlen(kx_anon_priority) + 1);
if (prio == NULL)
throw AuthFailureException("Not enough memory for GnuTLS priority string");
strcpy(prio, Security::GnuTLSPriority);
if (anon)
strcat(prio, kx_anon_priority);
ret = gnutls_priority_set_direct(session, prio, &err);
free(prio);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
throw AuthFailureException("gnutls_set_priority_direct failed");
}
if (anon) {
if (gnutls_anon_allocate_client_credentials(&anon_cred) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_anon_allocate_client_credentials failed");
if (gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_credentials_set failed");
vlog.debug("Anonymous session has been set");
} else {
if (gnutls_certificate_allocate_credentials(&cert_cred) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_certificate_allocate_credentials failed");
if (*cafile && gnutls_certificate_set_x509_trust_file(cert_cred,cafile,GNUTLS_X509_FMT_PEM) < 0)
throw AuthFailureException("load of CA cert failed");
/* Load previously saved certs */
char *homeDir = NULL;
int err;
if (getvnchomedir(&homeDir) == -1)
vlog.error("Could not obtain VNC home directory path");
else {
CharArray caSave(strlen(homeDir) + 19 + 1);
sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir);
delete [] homeDir;
err = gnutls_certificate_set_x509_trust_file(cert_cred, caSave.buf,
GNUTLS_X509_FMT_PEM);
if (err < 0)
vlog.debug("Failed to load saved server certificates from %s", caSave.buf);
}
if (*crlfile && gnutls_certificate_set_x509_crl_file(cert_cred,crlfile,GNUTLS_X509_FMT_PEM) < 0)
throw AuthFailureException("load of CRL failed");
if (gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_credentials_set failed");
if (gnutls_server_name_set(session, GNUTLS_NAME_DNS,
client->getServerName(),
strlen(client->getServerName())) != GNUTLS_E_SUCCESS)
vlog.error("Failed to configure the server name for TLS handshake");
vlog.debug("X509 session has been set");
}
}
void CSecurityTLS::checkSession()
{
const unsigned allowed_errors = GNUTLS_CERT_INVALID |
GNUTLS_CERT_SIGNER_NOT_FOUND |
GNUTLS_CERT_SIGNER_NOT_CA;
unsigned int status;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size = 0;
int err;
gnutls_datum_t info;
if (anon)
return;
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
throw AuthFailureException("unsupported certificate type");
err = gnutls_certificate_verify_peers2(session, &status);
if (err != 0) {
vlog.error("server certificate verification failed: %s", gnutls_strerror(err));
throw AuthFailureException("server certificate verification failed");
}
if (status & GNUTLS_CERT_REVOKED)
throw AuthFailureException("server certificate has been revoked");
#ifndef WITHOUT_X509_TIMES
if (status & GNUTLS_CERT_NOT_ACTIVATED)
throw AuthFailureException("server certificate has not been activated");
if (status & GNUTLS_CERT_EXPIRED) {
vlog.debug("server certificate has expired");
if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate has expired",
"The certificate of the server has expired, "
"do you want to continue?"))
throw AuthFailureException("server certificate has expired");
}
#endif
/* Process other errors later */
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
if (!cert_list_size)
throw AuthFailureException("empty certificate chain");
/* Process only server's certificate, not issuer's certificate */
gnutls_x509_crt_t crt;
gnutls_x509_crt_init(&crt);
if (gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
throw AuthFailureException("decoding of certificate failed");
if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
char buf[255];
vlog.debug("hostname mismatch");
snprintf(buf, sizeof(buf), "Hostname (%s) does not match any certificate, "
"do you want to continue?", client->getServerName());
buf[sizeof(buf) - 1] = '\0';
if (!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf))
throw AuthFailureException("hostname mismatch");
}
if (status == 0) {
/* Everything is fine (hostname + verification) */
gnutls_x509_crt_deinit(crt);
return;
}
if (status & GNUTLS_CERT_INVALID)
vlog.debug("server certificate invalid");
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
vlog.debug("server cert signer not found");
if (status & GNUTLS_CERT_SIGNER_NOT_CA)
vlog.debug("server cert signer not CA");
if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
throw AuthFailureException("The server certificate uses an insecure algorithm");
if ((status & (~allowed_errors)) != 0) {
/* No other errors are allowed */
vlog.debug("GNUTLS status of certificate verification: %u", status);
throw AuthFailureException("Invalid status of server certificate verification");
}
vlog.debug("Saved server certificates don't match");
if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) {
/*
* GNUTLS doesn't correctly export gnutls_free symbol which is
* a function pointer. Linking with Visual Studio 2008 Express will
* fail when you call gnutls_free().
*/
#if WIN32
free(info.data);
#else
gnutls_free(info.data);
#endif
throw AuthFailureException("Could not find certificate to display");
}
size_t out_size = 0;
char *out_buf = NULL;
char *certinfo = NULL;
int len = 0;
vlog.debug("certificate issuer unknown");
len = snprintf(NULL, 0, "This certificate has been signed by an unknown "
"authority:\n\n%s\n\nDo you want to save it and "
"continue?\n ", info.data);
if (len < 0)
AuthFailureException("certificate decoding error");
vlog.debug("%s", info.data);
certinfo = new char[len];
if (certinfo == NULL)
throw AuthFailureException("Out of memory");
snprintf(certinfo, len, "This certificate has been signed by an unknown "
"authority:\n\n%s\n\nDo you want to save it and "
"continue? ", info.data);
for (int i = 0; i < len - 1; i++)
if (certinfo[i] == ',' && certinfo[i + 1] == ' ')
certinfo[i] = '\n';
if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown",
certinfo)) {
delete [] certinfo;
throw AuthFailureException("certificate issuer unknown");
}
delete [] certinfo;
if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size)
== GNUTLS_E_SHORT_MEMORY_BUFFER)
AuthFailureException("Out of memory");
// Save cert
out_buf = new char[out_size];
if (out_buf == NULL)
AuthFailureException("Out of memory");
if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size) < 0)
AuthFailureException("certificate issuer unknown, and certificate "
"export failed");
char *homeDir = NULL;
if (getvnchomedir(&homeDir) == -1)
vlog.error("Could not obtain VNC home directory path");
else {
FILE *f;
CharArray caSave(strlen(homeDir) + 1 + 19);
sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir);
delete [] homeDir;
f = fopen(caSave.buf, "a+");
if (!f)
msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed",
"Could not save the certificate");
else {
fprintf(f, "%s\n", out_buf);
fclose(f);
}
}
delete [] out_buf;
gnutls_x509_crt_deinit(crt);
/*
* GNUTLS doesn't correctly export gnutls_free symbol which is
* a function pointer. Linking with Visual Studio 2008 Express will
* fail when you call gnutls_free().
*/
#if WIN32
free(info.data);
#else
gnutls_free(info.data);
#endif
}

77
common/rfb/CSecurityTLS.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __C_SECURITY_TLS_H__
#define __C_SECURITY_TLS_H__
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef HAVE_GNUTLS
#error "This header should not be compiled without HAVE_GNUTLS defined"
#endif
#include <rfb/CSecurity.h>
#include <rfb/SSecurityVeNCrypt.h>
#include <rfb/Security.h>
#include <rfb/UserMsgBox.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
#include <gnutls/gnutls.h>
namespace rfb {
class UserMsgBox;
class CSecurityTLS : public CSecurity {
public:
CSecurityTLS(bool _anon);
virtual ~CSecurityTLS();
virtual bool processMsg(CConnection* cc);
virtual int getType() const { return anon ? secTypeTLSNone : secTypeX509None; }
virtual const char* description() const
{ return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
virtual bool isSecure() const { return !anon; }
static void setDefaults();
static StringParameter X509CA;
static StringParameter X509CRL;
static UserMsgBox *msg;
protected:
void shutdown(bool needbye);
void freeResources();
void setParam();
void checkSession();
CConnection *client;
private:
gnutls_session_t session;
gnutls_anon_client_credentials_t anon_cred;
gnutls_certificate_credentials_t cert_cred;
bool anon;
char *cafile, *crlfile;
rdr::InStream* fis;
rdr::OutStream* fos;
};
}
#endif

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2006 OCCAM Financial Technology
* Copyright (C) 2005-2006 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CSecurityVeNCrypt
//
#include <rfb/Exception.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
#include <rfb/CConnection.h>
#include <rfb/CSecurityVeNCrypt.h>
#include <rfb/LogWriter.h>
#include <list>
using namespace rfb;
using namespace rdr;
using namespace std;
static LogWriter vlog("CVeNCrypt");
CSecurityVeNCrypt::CSecurityVeNCrypt(SecurityClient* sec) : csecurity(NULL), security(sec)
{
haveRecvdMajorVersion = false;
haveRecvdMinorVersion = false;
haveSentVersion = false;
haveAgreedVersion = false;
haveListOfTypes = false;
haveNumberOfTypes = false;
haveChosenType = false;
majorVersion = 0;
minorVersion = 0;
chosenType = secTypeVeNCrypt;
nAvailableTypes = 0;
availableTypes = NULL;
iAvailableType = 0;
}
CSecurityVeNCrypt::~CSecurityVeNCrypt()
{
if (availableTypes)
delete[] availableTypes;
}
bool CSecurityVeNCrypt::processMsg(CConnection* cc)
{
InStream* is = cc->getInStream();
OutStream* os = cc->getOutStream();
/* get major, minor versions, send what we can support (or 0.0 for can't support it) */
if (!haveRecvdMajorVersion) {
majorVersion = is->readU8();
haveRecvdMajorVersion = true;
return false;
}
if (!haveRecvdMinorVersion) {
minorVersion = is->readU8();
haveRecvdMinorVersion = true;
}
/* major version in upper 8 bits and minor version in lower 8 bits */
U16 Version = (((U16) majorVersion) << 8) | ((U16) minorVersion);
if (!haveSentVersion) {
/* Currently we don't support former VeNCrypt 0.1 */
if (Version >= 0x0002) {
majorVersion = 0;
minorVersion = 2;
os->writeU8(majorVersion);
os->writeU8(minorVersion);
os->flush();
} else {
/* Send 0.0 to indicate no support */
majorVersion = 0;
minorVersion = 0;
os->writeU8(0);
os->writeU8(0);
os->flush();
throw AuthFailureException("The server reported an unsupported VeNCrypt version");
}
haveSentVersion = true;
return false;
}
/* Check that the server is OK */
if (!haveAgreedVersion) {
if (is->readU8())
throw AuthFailureException("The server reported it could not support the "
"VeNCrypt version");
haveAgreedVersion = true;
return false;
}
/* get a number of types */
if (!haveNumberOfTypes) {
nAvailableTypes = is->readU8();
iAvailableType = 0;
if (!nAvailableTypes)
throw AuthFailureException("The server reported no VeNCrypt sub-types");
availableTypes = new rdr::U32[nAvailableTypes];
haveNumberOfTypes = true;
return false;
}
if (nAvailableTypes) {
/* read in the types possible */
if (!haveListOfTypes) {
if (is->checkNoWait(4)) {
availableTypes[iAvailableType++] = is->readU32();
haveListOfTypes = (iAvailableType >= nAvailableTypes);
vlog.debug("Server offers security type %s (%d)",
secTypeName(availableTypes[iAvailableType - 1]),
availableTypes[iAvailableType - 1]);
if (!haveListOfTypes)
return false;
} else
return false;
}
/* make a choice and send it to the server, meanwhile set up the stack */
if (!haveChosenType) {
chosenType = secTypeInvalid;
U8 i;
list<U32>::iterator j;
list<U32> secTypes;
secTypes = security->GetEnabledExtSecTypes();
/* Honor server's security type order */
for (i = 0; i < nAvailableTypes; i++) {
for (j = secTypes.begin(); j != secTypes.end(); j++) {
if (*j == availableTypes[i]) {
chosenType = *j;
break;
}
}
if (chosenType != secTypeInvalid)
break;
}
vlog.info("Choosing security type %s (%d)", secTypeName(chosenType),
chosenType);
/* Set up the stack according to the chosen type: */
if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt)
throw AuthFailureException("No valid VeNCrypt sub-type");
csecurity = security->GetCSecurity(chosenType);
/* send chosen type to server */
os->writeU32(chosenType);
os->flush();
haveChosenType = true;
}
} else {
/*
* Server told us that there are 0 types it can support - this should not
* happen, since if the server supports 0 sub-types, it doesn't support
* this security type
*/
throw AuthFailureException("The server reported 0 VeNCrypt sub-types");
}
return csecurity->processMsg(cc);
}
const char* CSecurityVeNCrypt::description() const
{
if (csecurity)
return csecurity->description();
return "VeNCrypt";
}
bool CSecurityVeNCrypt::isSecure() const
{
if (csecurity && csecurity->isSecure())
return true;
return false;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2005-2006 Martin Koegler
* Copyright (C) 2006 OCCAM Financial Technology
* Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CSecurityVeNCrypt
//
#ifndef __CSECURITYVENCRYPT_H__
#define __CSECURITYVENCRYPT_H__
#include <rfb/CSecurity.h>
#include <rfb/SecurityClient.h>
#include <rdr/types.h>
namespace rfb {
class CSecurityVeNCrypt : public CSecurity {
public:
CSecurityVeNCrypt(SecurityClient* sec);
~CSecurityVeNCrypt();
virtual bool processMsg(CConnection* cc);// { return true; }
int getType() const {return chosenType;}
virtual const char* description() const;
virtual bool isSecure() const;
protected:
CSecurity *csecurity;
SecurityClient *security;
bool haveRecvdMajorVersion;
bool haveRecvdMinorVersion;
bool haveSentVersion;
bool haveAgreedVersion;
bool haveListOfTypes;
bool haveNumberOfTypes;
bool haveChosenType;
rdr::U8 majorVersion, minorVersion;
rdr::U32 chosenType;
rdr::U8 nAvailableTypes;
rdr::U32 *availableTypes;
rdr::U8 iAvailableType;
};
}
#endif

View File

@ -0,0 +1,67 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
//
// CSecurityVncAuth
//
// XXX not thread-safe, because d3des isn't - do we need to worry about this?
//
#include <string.h>
#include <stdio.h>
#include <rfb/CConnection.h>
#include <rfb/Password.h>
#include <rfb/CSecurityVncAuth.h>
#include <rfb/util.h>
#include <rfb/Security.h>
extern "C" {
#include <rfb/d3des.h>
}
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
using namespace rfb;
static const int vncAuthChallengeSize = 16;
bool CSecurityVncAuth::processMsg(CConnection* cc)
{
rdr::InStream* is = cc->getInStream();
rdr::OutStream* os = cc->getOutStream();
// Read the challenge & obtain the user's password
rdr::U8 challenge[vncAuthChallengeSize];
is->readBytes(challenge, vncAuthChallengeSize);
PlainPasswd passwd;
(CSecurity::upg)->getUserPasswd(cc->isSecure(), 0, &passwd.buf);
// Calculate the correct response
rdr::U8 key[8];
int pwdLen = strlen(passwd.buf);
for (int i=0; i<8; i++)
key[i] = i<pwdLen ? passwd.buf[i] : 0;
deskey(key, EN0);
for (int j = 0; j < vncAuthChallengeSize; j += 8)
des(challenge+j, challenge+j);
// Return the response to the server
os->writeBytes(challenge, vncAuthChallengeSize);
os->flush();
return true;
}

View File

@ -0,0 +1,35 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_CSECURITYVNCAUTH_H__
#define __RFB_CSECURITYVNCAUTH_H__
#include <rfb/CSecurity.h>
#include <rfb/Security.h>
namespace rfb {
class CSecurityVncAuth : public CSecurity {
public:
CSecurityVncAuth(void) {}
virtual ~CSecurityVncAuth() {}
virtual bool processMsg(CConnection* cc);
virtual int getType() const {return secTypeVncAuth;};
virtual const char* description() const {return "No Encryption";}
};
}
#endif

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