Skip to content
GitLab
Explore
Sign in
Register
Commits on Source (2)
New upstream version 1.10.0
· 3e3ef09c
Joachim Falk
authored
Dec 08, 2019
3e3ef09c
New upstream version 1.10.0+dfsg
· b149914d
Joachim Falk
authored
Dec 08, 2019
b149914d
Show whitespace changes
Inline
Side-by-side
.gitignore
0 → 100644
View file @
b149914d
*.[ao]
*.mo
*.la
*.lo
.deps
.libs
CMakeFiles
CMakeCache.txt
*.cmake
Makefile
Makefile.in
config.h
.travis.yml
deleted
100644 → 0
View file @
a7d5dd12
language
:
-
c++
-
java
# Travis is still stuck on Ubuntu 14.04, which has a too old FLTK
before_install
:
-
wget http://fltk.org/pub/fltk/1.3.4/fltk-1.3.4-2-source.tar.gz
-
tar -xvf fltk-1.3.4-2-source.tar.gz
-
pushd fltk-1.3.4-2
-
./configure --prefix=/usr --enable-shared
-
make -j2
-
sudo make install
-
popd
script
:
-
cmake . && make
-
cd java && cmake . && make
BUILDING.txt
View file @
b149914d
...
...
@@ -158,8 +158,8 @@ The following procedure will build both the TigerVNC Viewer and a
"legacy-friendly" version of the TigerVNC Server:
cd {build_directory}
sh {source_directory}/contrib/xorg/build-xorg init
sh {source_directory}/contrib/xorg/build-xorg build [additional CMake flags]
ba
sh {source_directory}/contrib/xorg/build-xorg init
ba
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
...
...
CMakeLists.txt
View file @
b149914d
...
...
@@ -2,7 +2,7 @@
# Setup
#
cmake_minimum_required
(
VERSION 2.8
)
cmake_minimum_required
(
VERSION 2.8
.11
)
if
(
POLICY CMP0022
)
cmake_policy
(
SET CMP0022 OLD
)
endif
()
...
...
@@ -21,10 +21,10 @@ include(CheckCSourceRuns)
include
(
CMakeMacroLibtoolFile
)
project
(
tigervnc
)
set
(
VERSION 1.
9
.0
)
set
(
VERSION 1.
10
.0
)
# The RC version must always be four comma-separated numbers
set
(
RCVERSION 1,
9
,0,0
)
set
(
RCVERSION 1,
10
,0,0
)
# Installation paths
set
(
BIN_DIR
"
${
CMAKE_INSTALL_PREFIX
}
/bin"
)
...
...
@@ -43,9 +43,7 @@ if(MSVC)
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
}
)
STRING
(
TIMESTAMP BUILD_TIMESTAMP
"%Y-%m-%d %H:%M"
UTC
)
endif
()
# Default to optimised builds instead of debug ones. Our code has no bugs ;)
...
...
@@ -76,8 +74,8 @@ 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"
)
set
(
CMAKE_C_FLAGS
"
${
CMAKE_C_FLAGS
}
-Werror
-Werror=vla
"
)
set
(
CMAKE_CXX_FLAGS
"
${
CMAKE_CXX_FLAGS
}
-Werror
-Werror=vla
"
)
ENDIF
()
option
(
ENABLE_ASAN
"Enable address sanitizer support"
OFF
)
...
...
README.rst
View file @
b149914d
...
...
@@ -34,7 +34,7 @@ Incomplete and generally out of date copyright list::
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-201
8
TigerVNC Team
Copyright (C) 2009-201
9
TigerVNC Team
All Rights Reserved.
This software is distributed under the GNU General Public Licence as published
...
...
cmake/StaticBuild.cmake
View file @
b149914d
...
...
@@ -19,10 +19,7 @@ if(BUILD_STATIC)
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
)
...
...
@@ -91,7 +88,7 @@ if(BUILD_STATIC)
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"
)
set
(
FLTK_LIBRARIES
"
${
FLTK_LIBRARIES
}
-Wl,-Bstatic -lXcursor -lXfixes -lXft -lfontconfig -lexpat -lfreetype -lpng -lbz2
-luuid
-lXrender -lXext -lXinerama -Wl,-Bdynamic"
)
endif
()
set
(
FLTK_LIBRARIES
"
${
FLTK_LIBRARIES
}
-lX11"
)
...
...
common/network/Socket.h
View file @
b149914d
...
...
@@ -144,15 +144,6 @@ namespace network {
// 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
;};
};
}
...
...
common/network/TcpSocket.cxx
View file @
b149914d
...
...
@@ -736,7 +736,7 @@ char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
buffer
+
1
,
sizeof
(
buffer
)
-
2
,
NULL
,
0
,
NI_NUMERICHOST
);
strcat
(
buffer
,
"]"
);
addr
.
buf
=
rfb
::
strDup
(
buffer
);
}
else
if
(
p
.
address
.
u
.
sa
.
sa_family
==
AF_UNSPEC
)
}
else
addr
.
buf
=
rfb
::
strDup
(
""
);
char
action
;
...
...
common/rdr/FdInStream.cxx
View file @
b149914d
...
...
@@ -215,20 +215,10 @@ int FdInStream::readWithTimeoutOrCallback(void* buf, int len, bool wait)
if
(
timing
)
{
gettimeofday
(
&
after
,
0
);
// fprintf(stderr,"%d.%06d\n",(after.tv_sec - before.tv_sec),
// (after.tv_usec - before.tv_usec));
int
newTimeWaited
=
((
after
.
tv_sec
-
before
.
tv_sec
)
*
10000
+
(
after
.
tv_usec
-
before
.
tv_usec
)
/
100
);
int
newKbits
=
n
*
8
/
1000
;
// if (newTimeWaited == 0) {
// fprintf(stderr,"new kbps infinite t %d k %d\n",
// newTimeWaited, newKbits);
// } else {
// fprintf(stderr,"new kbps %d t %d k %d\n",
// newKbits * 10000 / newTimeWaited, newTimeWaited, newKbits);
// }
// limit rate to between 10kbit/s and 40Mbit/s
if
(
newTimeWaited
>
newKbits
*
1000
)
newTimeWaited
=
newKbits
*
1000
;
...
...
common/rdr/RandomStream.cxx
View file @
b149914d
...
...
@@ -18,6 +18,7 @@
#include
<rdr/RandomStream.h>
#include
<rdr/Exception.h>
#include
<rfb/LogWriter.h>
#include
<time.h>
#include
<stdlib.h>
#ifndef WIN32
...
...
@@ -30,6 +31,8 @@
#endif
#endif
static
rfb
::
LogWriter
vlog
(
"RandomStream"
);
using
namespace
rdr
;
const
int
DEFAULT_BUF_LEN
=
256
;
...
...
@@ -46,11 +49,11 @@ RandomStream::RandomStream()
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
"
);
vlog
.
error
(
"
unable to create keyset"
);
provider
=
0
;
}
}
else
{
fprintf
(
stderr
,
"RandomStream:
unable to acquire context
\n
"
);
vlog
.
error
(
"
unable to acquire context"
);
provider
=
0
;
}
}
...
...
@@ -65,7 +68,7 @@ RandomStream::RandomStream()
{
#endif
#endif
fprintf
(
stderr
,
"RandomStream: warning:
no OS supplied random source - using rand()
\n
"
);
vlog
.
error
(
"
no OS supplied random source - using rand()"
);
seed
+=
(
unsigned
int
)
time
(
0
)
+
getpid
()
+
getpid
()
*
987654
+
rand
();
srand
(
seed
);
}
...
...
common/rdr/SubstitutingInStream.h
deleted
100644 → 0
View file @
a7d5dd12
/* 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
common/rdr/ZlibOutStream.cxx
View file @
b149914d
...
...
@@ -21,11 +21,14 @@
#include
<rdr/ZlibOutStream.h>
#include
<rdr/Exception.h>
#include
<rfb/LogWriter.h>
#include
<zlib.h>
#undef ZLIBOUT_DEBUG
static
rfb
::
LogWriter
vlog
(
"ZlibOutStream"
);
using
namespace
rdr
;
enum
{
DEFAULT_BUF_SIZE
=
16384
};
...
...
@@ -85,7 +88,7 @@ void ZlibOutStream::flush()
zs
->
avail_in
=
ptr
-
start
;
#ifdef ZLIBOUT_DEBUG
fprintf
(
stderr
,
"zos
flush: avail_in %d
\n
"
,
zs
->
avail_in
);
vlog
.
debug
(
"
flush: avail_in %d"
,
zs
->
avail_in
);
#endif
// Force out everything from the zlib encoder
...
...
@@ -98,7 +101,7 @@ void ZlibOutStream::flush()
int
ZlibOutStream
::
overrun
(
int
itemSize
,
int
nItems
)
{
#ifdef ZLIBOUT_DEBUG
fprintf
(
stderr
,
"zos
overrun
\n
"
);
vlog
.
debug
(
"
overrun"
);
#endif
if
(
itemSize
>
bufSize
)
...
...
@@ -120,7 +123,7 @@ int ZlibOutStream::overrun(int itemSize, int nItems)
}
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
"
);
vlog
.
info
(
"z out buf not full, but in data not consumed"
);
memmove
(
start
,
zs
->
next_in
,
ptr
-
zs
->
next_in
);
offset
+=
zs
->
next_in
-
start
;
ptr
-=
zs
->
next_in
-
start
;
...
...
@@ -149,7 +152,7 @@ void ZlibOutStream::deflate(int flush)
zs
->
avail_out
=
underlying
->
getend
()
-
underlying
->
getptr
();
#ifdef ZLIBOUT_DEBUG
fprintf
(
stderr
,
"zos:
calling deflate, avail_in %d, avail_out %d
\n
"
,
vlog
.
debug
(
"
calling deflate, avail_in %d, avail_out %d"
,
zs
->
avail_in
,
zs
->
avail_out
);
#endif
...
...
@@ -163,7 +166,7 @@ void ZlibOutStream::deflate(int flush)
}
#ifdef ZLIBOUT_DEBUG
fprintf
(
stderr
,
"zos:
after deflate: %d bytes
\n
"
,
vlog
.
debug
(
"
after deflate: %d bytes"
,
zs
->
next_out
-
underlying
->
getptr
());
#endif
...
...
@@ -177,7 +180,7 @@ void ZlibOutStream::checkCompressionLevel()
if
(
newLevel
!=
compressionLevel
)
{
#ifdef ZLIBOUT_DEBUG
fprintf
(
stderr
,
"zos
change: avail_in %d
\n
"
,
zs
->
avail_in
);
vlog
.
debug
(
"
change: avail_in %d"
,
zs
->
avail_in
);
#endif
// zlib is just horribly stupid. It does an implicit flush on
...
...
common/rfb/Blacklist.cxx
View file @
b149914d
...
...
@@ -20,13 +20,19 @@
using
namespace
rfb
;
IntParameter
Blacklist
::
threshold
(
"BlacklistThreshold"
,
"The number of unauthenticated connection attempts allowed from any "
"individual host before that host is black-listed"
,
BoolParameter
enabled
(
"UseBlacklist"
,
"Temporarily reject connections from a host if it "
"repeatedly fails to authenticate."
,
true
);
IntParameter
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."
,
IntParameter
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
);
...
...
@@ -42,6 +48,9 @@ Blacklist::~Blacklist() {
}
bool
Blacklist
::
isBlackmarked
(
const
char
*
name
)
{
if
(
!
enabled
)
return
false
;
BlacklistMap
::
iterator
i
=
blm
.
find
(
name
);
if
(
i
==
blm
.
end
())
{
// Entry is not already black-marked.
...
...
common/rfb/Blacklist.h
View file @
b149914d
...
...
@@ -67,9 +67,6 @@ namespace rfb {
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
{
...
...
common/rfb/CConnection.cxx
View file @
b149914d
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-201
7
Pierre Ossman for Cendio AB
* Copyright 2011-201
9
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
...
...
@@ -16,14 +16,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include
<assert.h>
#include
<stdio.h>
#include
<string.h>
#include
<rfb/Exception.h>
#include
<rfb/clipboardTypes.h>
#include
<rfb/fenceTypes.h>
#include
<rfb/CMsgReader.h>
#include
<rfb/CMsgWriter.h>
#include
<rfb/CSecurity.h>
#include
<rfb/Decoder.h>
#include
<rfb/Security.h>
#include
<rfb/SecurityClient.h>
#include
<rfb/CConnection.h>
...
...
@@ -39,21 +42,32 @@ using namespace rfb;
static
LogWriter
vlog
(
"CConnection"
);
CConnection
::
CConnection
()
:
csecurity
(
0
),
is
(
0
),
os
(
0
),
reader_
(
0
),
writer_
(
0
),
:
csecurity
(
0
),
supportsLocalCursor
(
false
),
supportsDesktopResize
(
false
),
supportsLEDState
(
false
),
is
(
0
),
os
(
0
),
reader_
(
0
),
writer_
(
0
),
shared
(
false
),
state_
(
RFBSTATE_UNINITIALISED
),
useProtocol3_3
(
false
),
framebuffer
(
NULL
),
decoder
(
this
)
state_
(
RFBSTATE_UNINITIALISED
),
pendingPFChange
(
false
),
preferredEncoding
(
encodingTight
),
compressLevel
(
2
),
qualityLevel
(
-
1
),
formatChange
(
false
),
encodingChange
(
false
),
firstUpdate
(
true
),
pendingUpdate
(
false
),
continuousUpdates
(
false
),
forceNonincremental
(
true
),
framebuffer
(
NULL
),
decoder
(
this
),
serverClipboard
(
NULL
),
hasLocalClipboard
(
false
)
{
}
CConnection
::~
CConnection
()
{
setFramebuffer
(
NULL
);
if
(
csecurity
)
csecurity
->
destroy
();
if
(
csecurity
)
delete
csecurity
;
delete
reader_
;
reader_
=
0
;
delete
writer_
;
writer_
=
0
;
strFree
(
serverClipboard
);
}
void
CConnection
::
setStreams
(
rdr
::
InStream
*
is_
,
rdr
::
OutStream
*
os_
)
...
...
@@ -66,6 +80,11 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
{
decoder
.
flush
();
if
(
fb
)
{
assert
(
fb
->
width
()
==
server
.
width
());
assert
(
fb
->
height
()
==
server
.
height
());
}
if
((
framebuffer
!=
NULL
)
&&
(
fb
!=
NULL
))
{
Rect
rect
;
...
...
@@ -127,35 +146,51 @@ void CConnection::processMsg()
void
CConnection
::
processVersionMsg
()
{
char
verStr
[
27
];
// FIXME: gcc has some bug in format-overflow
int
majorVersion
;
int
minorVersion
;
vlog
.
debug
(
"reading protocol version"
);
bool
done
;
if
(
!
cp
.
readVersion
(
is
,
&
done
))
{
if
(
!
is
->
checkNoWait
(
12
))
return
;
is
->
readBytes
(
verStr
,
12
);
verStr
[
12
]
=
'\0'
;
if
(
sscanf
(
verStr
,
"RFB %03d.%03d
\n
"
,
&
majorVersion
,
&
minorVersion
)
!=
2
)
{
state_
=
RFBSTATE_INVALID
;
throw
Exception
(
"reading version failed: not an RFB server?"
);
}
if
(
!
done
)
return
;
server
.
setVersion
(
majorVersion
,
minorVersion
);
vlog
.
info
(
"Server supports RFB protocol version %d.%d"
,
cp
.
majorVersion
,
cp
.
minorVersion
);
server
.
majorVersion
,
server
.
minorVersion
);
// The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
if
(
cp
.
beforeVersion
(
3
,
3
))
{
if
(
server
.
beforeVersion
(
3
,
3
))
{
vlog
.
error
(
"Server gave unsupported RFB protocol version %d.%d"
,
cp
.
majorVersion
,
cp
.
minorVersion
);
server
.
majorVersion
,
server
.
minorVersion
);
state_
=
RFBSTATE_INVALID
;
throw
Exception
(
"Server gave unsupported RFB protocol version %d.%d"
,
cp
.
majorVersion
,
cp
.
minorVersion
);
}
else
if
(
u
se
Protocol3_3
||
cp
.
beforeVersion
(
3
,
7
))
{
cp
.
setVersion
(
3
,
3
);
}
else
if
(
cp
.
afterVersion
(
3
,
8
))
{
cp
.
setVersion
(
3
,
8
);
server
.
majorVersion
,
server
.
minorVersion
);
}
else
if
(
se
rver
.
beforeVersion
(
3
,
7
))
{
server
.
setVersion
(
3
,
3
);
}
else
if
(
server
.
afterVersion
(
3
,
8
))
{
server
.
setVersion
(
3
,
8
);
}
cp
.
writeVersion
(
os
);
sprintf
(
verStr
,
"RFB %03d.%03d
\n
"
,
server
.
majorVersion
,
server
.
minorVersion
);
os
->
writeBytes
(
verStr
,
12
);
os
->
flush
();
state_
=
RFBSTATE_SECURITY_TYPES
;
vlog
.
info
(
"Using RFB protocol version %d.%d"
,
cp
.
majorVersion
,
cp
.
minorVersion
);
server
.
majorVersion
,
server
.
minorVersion
);
}
...
...
@@ -168,7 +203,7 @@ void CConnection::processSecurityTypesMsg()
std
::
list
<
rdr
::
U8
>
secTypes
;
secTypes
=
security
.
GetEnabledSecTypes
();
if
(
cp
.
isVersion
(
3
,
3
))
{
if
(
server
.
isVersion
(
3
,
3
))
{
// legacy 3.3 server may only offer "vnc authentication" or "none"
...
...
@@ -234,14 +269,14 @@ void CConnection::processSecurityTypesMsg()
}
state_
=
RFBSTATE_SECURITY
;
csecurity
=
security
.
GetCSecurity
(
secType
);
csecurity
=
security
.
GetCSecurity
(
this
,
secType
);
processSecurityMsg
();
}
void
CConnection
::
processSecurityMsg
()
{
vlog
.
debug
(
"processing security message"
);
if
(
csecurity
->
processMsg
(
this
))
{
if
(
csecurity
->
processMsg
())
{
state_
=
RFBSTATE_SECURITY_RESULT
;
processSecurityResultMsg
();
}
...
...
@@ -251,7 +286,7 @@ void CConnection::processSecurityResultMsg()
{
vlog
.
debug
(
"processing security result message"
);
int
result
;
if
(
cp
.
beforeVersion
(
3
,
8
)
&&
csecurity
->
getType
()
==
secTypeNone
)
{
if
(
server
.
beforeVersion
(
3
,
8
)
&&
csecurity
->
getType
()
==
secTypeNone
)
{
result
=
secResultOK
;
}
else
{
if
(
!
is
->
checkNoWait
(
1
))
return
;
...
...
@@ -271,7 +306,7 @@ void CConnection::processSecurityResultMsg()
throw
Exception
(
"Unknown security result from server"
);
}
state_
=
RFBSTATE_INVALID
;
if
(
cp
.
beforeVersion
(
3
,
8
))
if
(
server
.
beforeVersion
(
3
,
8
))
throw
AuthFailureException
();
CharArray
reason
(
is
->
readString
());
throw
AuthFailureException
(
reason
.
buf
);
...
...
@@ -295,7 +330,7 @@ void CConnection::securityCompleted()
{
state_
=
RFBSTATE_INITIALISATION
;
reader_
=
new
CMsgReader
(
this
,
is
);
writer_
=
new
CMsgWriter
(
&
cp
,
os
);
writer_
=
new
CMsgWriter
(
&
server
,
os
);
vlog
.
debug
(
"Authentication success!"
);
authSuccess
();
writer_
->
writeClientInit
(
shared
);
...
...
@@ -306,6 +341,16 @@ void CConnection::setDesktopSize(int w, int h)
decoder
.
flush
();
CMsgHandler
::
setDesktopSize
(
w
,
h
);
if
(
continuousUpdates
)
writer
()
->
writeEnableContinuousUpdates
(
true
,
0
,
0
,
server
.
width
(),
server
.
height
());
resizeFramebuffer
();
assert
(
framebuffer
!=
NULL
);
assert
(
framebuffer
->
width
()
==
server
.
width
());
assert
(
framebuffer
->
height
()
==
server
.
height
());
}
void
CConnection
::
setExtendedDesktopSize
(
unsigned
reason
,
...
...
@@ -316,6 +361,59 @@ void CConnection::setExtendedDesktopSize(unsigned reason,
decoder
.
flush
();
CMsgHandler
::
setExtendedDesktopSize
(
reason
,
result
,
w
,
h
,
layout
);
if
(
continuousUpdates
)
writer
()
->
writeEnableContinuousUpdates
(
true
,
0
,
0
,
server
.
width
(),
server
.
height
());
resizeFramebuffer
();
assert
(
framebuffer
!=
NULL
);
assert
(
framebuffer
->
width
()
==
server
.
width
());
assert
(
framebuffer
->
height
()
==
server
.
height
());
}
void
CConnection
::
endOfContinuousUpdates
()
{
CMsgHandler
::
endOfContinuousUpdates
();
// We've gotten the marker for a format change, so make the pending
// one active
if
(
pendingPFChange
)
{
server
.
setPF
(
pendingPF
);
pendingPFChange
=
false
;
// We might have another change pending
if
(
formatChange
)
requestNewUpdate
();
}
}
void
CConnection
::
serverInit
(
int
width
,
int
height
,
const
PixelFormat
&
pf
,
const
char
*
name
)
{
CMsgHandler
::
serverInit
(
width
,
height
,
pf
,
name
);
state_
=
RFBSTATE_NORMAL
;
vlog
.
debug
(
"initialisation done"
);
initDone
();
assert
(
framebuffer
!=
NULL
);
assert
(
framebuffer
->
width
()
==
server
.
width
());
assert
(
framebuffer
->
height
()
==
server
.
height
());
// We want to make sure we call SetEncodings at least once
encodingChange
=
true
;
requestNewUpdate
();
// This initial update request is a bit of a corner case, so we need
// to help out setting the correct format here.
if
(
pendingPFChange
)
{
server
.
setPF
(
pendingPF
);
pendingPFChange
=
false
;
}
}
void
CConnection
::
readAndDecodeRect
(
const
Rect
&
r
,
int
encoding
,
...
...
@@ -328,6 +426,13 @@ void CConnection::readAndDecodeRect(const Rect& r, int encoding,
void
CConnection
::
framebufferUpdateStart
()
{
CMsgHandler
::
framebufferUpdateStart
();
assert
(
framebuffer
!=
NULL
);
// Note: This might not be true if continuous updates are supported
pendingUpdate
=
false
;
requestNewUpdate
();
}
void
CConnection
::
framebufferUpdateEnd
()
...
...
@@ -335,6 +440,25 @@ void CConnection::framebufferUpdateEnd()
decoder
.
flush
();
CMsgHandler
::
framebufferUpdateEnd
();
// A format change has been scheduled and we are now past the update
// with the old format. Time to active the new one.
if
(
pendingPFChange
&&
!
continuousUpdates
)
{
server
.
setPF
(
pendingPF
);
pendingPFChange
=
false
;
}
if
(
firstUpdate
)
{
if
(
server
.
supportsContinuousUpdates
)
{
vlog
.
info
(
"Enabling continuous updates"
);
continuousUpdates
=
true
;
writer
()
->
writeEnableContinuousUpdates
(
true
,
0
,
0
,
server
.
width
(),
server
.
height
());
}
firstUpdate
=
false
;
}
}
void
CConnection
::
dataRect
(
const
Rect
&
r
,
int
encoding
)
...
...
@@ -342,14 +466,190 @@ void CConnection::dataRect(const Rect& r, int encoding)
decoder
.
decodeRect
(
r
,
encoding
,
framebuffer
);
}
void
CConnection
::
serverCutText
(
const
char
*
str
)
{
hasLocalClipboard
=
false
;
strFree
(
serverClipboard
);
serverClipboard
=
NULL
;
serverClipboard
=
latin1ToUTF8
(
str
);
handleClipboardAnnounce
(
true
);
}
void
CConnection
::
handleClipboardCaps
(
rdr
::
U32
flags
,
const
rdr
::
U32
*
lengths
)
{
rdr
::
U32
sizes
[]
=
{
0
};
CMsgHandler
::
handleClipboardCaps
(
flags
,
lengths
);
writer
()
->
writeClipboardCaps
(
rfb
::
clipboardUTF8
|
rfb
::
clipboardRequest
|
rfb
::
clipboardPeek
|
rfb
::
clipboardNotify
|
rfb
::
clipboardProvide
,
sizes
);
}
void
CConnection
::
handleClipboardRequest
(
rdr
::
U32
flags
)
{
if
(
!
(
flags
&
rfb
::
clipboardUTF8
))
return
;
if
(
!
hasLocalClipboard
)
return
;
handleClipboardRequest
();
}
void
CConnection
::
handleClipboardPeek
(
rdr
::
U32
flags
)
{
if
(
!
hasLocalClipboard
)
return
;
if
(
server
.
clipboardFlags
()
&
rfb
::
clipboardNotify
)
writer
()
->
writeClipboardNotify
(
rfb
::
clipboardUTF8
);
}
void
CConnection
::
handleClipboardNotify
(
rdr
::
U32
flags
)
{
strFree
(
serverClipboard
);
serverClipboard
=
NULL
;
if
(
flags
&
rfb
::
clipboardUTF8
)
{
hasLocalClipboard
=
false
;
handleClipboardAnnounce
(
true
);
}
else
{
handleClipboardAnnounce
(
false
);
}
}
void
CConnection
::
handleClipboardProvide
(
rdr
::
U32
flags
,
const
size_t
*
lengths
,
const
rdr
::
U8
*
const
*
data
)
{
if
(
!
(
flags
&
rfb
::
clipboardUTF8
))
return
;
strFree
(
serverClipboard
);
serverClipboard
=
NULL
;
serverClipboard
=
convertLF
((
const
char
*
)
data
[
0
],
lengths
[
0
]);
// FIXME: Should probably verify that this data was actually requested
handleClipboardData
(
serverClipboard
);
}
void
CConnection
::
authSuccess
()
{
}
void
CConnection
::
serverInit
()
void
CConnection
::
initDone
()
{
}
void
CConnection
::
resizeFramebuffer
()
{
assert
(
false
);
}
void
CConnection
::
handleClipboardRequest
()
{
state_
=
RFBSTATE_NORMAL
;
vlog
.
debug
(
"initialisation done"
);
}
void
CConnection
::
handleClipboardAnnounce
(
bool
available
)
{
}
void
CConnection
::
handleClipboardData
(
const
char
*
data
)
{
}
void
CConnection
::
requestClipboard
()
{
if
(
serverClipboard
!=
NULL
)
{
handleClipboardData
(
serverClipboard
);
return
;
}
if
(
server
.
clipboardFlags
()
&
rfb
::
clipboardRequest
)
writer
()
->
writeClipboardRequest
(
rfb
::
clipboardUTF8
);
}
void
CConnection
::
announceClipboard
(
bool
available
)
{
hasLocalClipboard
=
available
;
if
(
server
.
clipboardFlags
()
&
rfb
::
clipboardNotify
)
writer
()
->
writeClipboardNotify
(
available
?
rfb
::
clipboardUTF8
:
0
);
else
{
if
(
available
)
handleClipboardRequest
();
}
}
void
CConnection
::
sendClipboardData
(
const
char
*
data
)
{
if
(
server
.
clipboardFlags
()
&
rfb
::
clipboardProvide
)
{
CharArray
filtered
(
convertCRLF
(
data
));
size_t
sizes
[
1
]
=
{
strlen
(
filtered
.
buf
)
+
1
};
const
rdr
::
U8
*
data
[
1
]
=
{
(
const
rdr
::
U8
*
)
filtered
.
buf
};
writer
()
->
writeClipboardProvide
(
rfb
::
clipboardUTF8
,
sizes
,
data
);
}
else
{
CharArray
latin1
(
utf8ToLatin1
(
data
));
writer
()
->
writeClientCutText
(
latin1
.
buf
);
}
}
void
CConnection
::
refreshFramebuffer
()
{
forceNonincremental
=
true
;
// Without continuous updates we have to make sure we only have a
// single update in flight, so we'll have to wait to do the refresh
if
(
continuousUpdates
)
requestNewUpdate
();
}
void
CConnection
::
setPreferredEncoding
(
int
encoding
)
{
if
(
preferredEncoding
==
encoding
)
return
;
preferredEncoding
=
encoding
;
encodingChange
=
true
;
}
int
CConnection
::
getPreferredEncoding
()
{
return
preferredEncoding
;
}
void
CConnection
::
setCompressLevel
(
int
level
)
{
if
(
compressLevel
==
level
)
return
;
compressLevel
=
level
;
encodingChange
=
true
;
}
void
CConnection
::
setQualityLevel
(
int
level
)
{
if
(
qualityLevel
==
level
)
return
;
qualityLevel
=
level
;
encodingChange
=
true
;
}
void
CConnection
::
setPF
(
const
PixelFormat
&
pf
)
{
if
(
server
.
pf
().
equal
(
pf
)
&&
!
formatChange
)
return
;
nextPF
=
pf
;
formatChange
=
true
;
}
void
CConnection
::
fence
(
rdr
::
U32
flags
,
unsigned
len
,
const
char
data
[])
...
...
@@ -364,3 +664,98 @@ void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
writer
()
->
writeFence
(
flags
,
len
,
data
);
}
// requestNewUpdate() requests an update from the server, having set the
// format and encoding appropriately.
void
CConnection
::
requestNewUpdate
()
{
if
(
formatChange
&&
!
pendingPFChange
)
{
/* Catch incorrect requestNewUpdate calls */
assert
(
!
pendingUpdate
||
continuousUpdates
);
// We have to make sure we switch the internal format at a safe
// time. For continuous updates we temporarily disable updates and
// look for a EndOfContinuousUpdates message to see when to switch.
// For classical updates we just got a new update right before this
// function was called, so we need to make sure we finish that
// update before we can switch.
pendingPFChange
=
true
;
pendingPF
=
nextPF
;
if
(
continuousUpdates
)
writer
()
->
writeEnableContinuousUpdates
(
false
,
0
,
0
,
0
,
0
);
writer
()
->
writeSetPixelFormat
(
pendingPF
);
if
(
continuousUpdates
)
writer
()
->
writeEnableContinuousUpdates
(
true
,
0
,
0
,
server
.
width
(),
server
.
height
());
formatChange
=
false
;
}
if
(
encodingChange
)
{
updateEncodings
();
encodingChange
=
false
;
}
if
(
forceNonincremental
||
!
continuousUpdates
)
{
pendingUpdate
=
true
;
writer
()
->
writeFramebufferUpdateRequest
(
Rect
(
0
,
0
,
server
.
width
(),
server
.
height
()),
!
forceNonincremental
);
}
forceNonincremental
=
false
;
}
// Ask for encodings based on which decoders are supported. Assumes higher
// encoding numbers are more desirable.
void
CConnection
::
updateEncodings
()
{
std
::
list
<
rdr
::
U32
>
encodings
;
if
(
supportsLocalCursor
)
{
encodings
.
push_back
(
pseudoEncodingCursorWithAlpha
);
encodings
.
push_back
(
pseudoEncodingVMwareCursor
);
encodings
.
push_back
(
pseudoEncodingCursor
);
encodings
.
push_back
(
pseudoEncodingXCursor
);
}
if
(
supportsDesktopResize
)
{
encodings
.
push_back
(
pseudoEncodingDesktopSize
);
encodings
.
push_back
(
pseudoEncodingExtendedDesktopSize
);
}
if
(
supportsLEDState
)
{
encodings
.
push_back
(
pseudoEncodingLEDState
);
encodings
.
push_back
(
pseudoEncodingVMwareLEDState
);
}
encodings
.
push_back
(
pseudoEncodingDesktopName
);
encodings
.
push_back
(
pseudoEncodingLastRect
);
encodings
.
push_back
(
pseudoEncodingExtendedClipboard
);
encodings
.
push_back
(
pseudoEncodingContinuousUpdates
);
encodings
.
push_back
(
pseudoEncodingFence
);
encodings
.
push_back
(
pseudoEncodingQEMUKeyEvent
);
if
(
Decoder
::
supported
(
preferredEncoding
))
{
encodings
.
push_back
(
preferredEncoding
);
}
encodings
.
push_back
(
encodingCopyRect
);
for
(
int
i
=
encodingMax
;
i
>=
0
;
i
--
)
{
if
((
i
!=
preferredEncoding
)
&&
Decoder
::
supported
(
i
))
encodings
.
push_back
(
i
);
}
if
(
compressLevel
>=
0
&&
compressLevel
<=
9
)
encodings
.
push_back
(
pseudoEncodingCompressLevel0
+
compressLevel
);
if
(
qualityLevel
>=
0
&&
qualityLevel
<=
9
)
encodings
.
push_back
(
pseudoEncodingQualityLevel0
+
qualityLevel
);
writer
()
->
writeSetEncodings
(
encodings
);
}
common/rfb/CConnection.h
View file @
b149914d
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-201
7
Pierre Ossman for Cendio AB
* Copyright 2011-201
9
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
...
...
@@ -62,10 +62,6 @@ namespace rfb {
// 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
...
...
@@ -100,6 +96,12 @@ namespace rfb {
int
w
,
int
h
,
const
ScreenSet
&
layout
);
virtual
void
endOfContinuousUpdates
();
virtual
void
serverInit
(
int
width
,
int
height
,
const
PixelFormat
&
pf
,
const
char
*
name
);
virtual
void
readAndDecodeRect
(
const
Rect
&
r
,
int
encoding
,
ModifiablePixelBuffer
*
pb
);
...
...
@@ -107,23 +109,90 @@ namespace rfb {
virtual
void
framebufferUpdateEnd
();
virtual
void
dataRect
(
const
Rect
&
r
,
int
encoding
);
virtual
void
serverCutText
(
const
char
*
str
);
// Methods to be overridden in a derived class
virtual
void
handleClipboardCaps
(
rdr
::
U32
flags
,
const
rdr
::
U32
*
lengths
);
virtual
void
handleClipboardRequest
(
rdr
::
U32
flags
);
virtual
void
handleClipboardPeek
(
rdr
::
U32
flags
);
virtual
void
handleClipboardNotify
(
rdr
::
U32
flags
);
virtual
void
handleClipboardProvide
(
rdr
::
U32
flags
,
const
size_t
*
lengths
,
const
rdr
::
U8
*
const
*
data
);
// getIdVerifier() returns the identity verifier associated with the connection.
// Ownership of the IdentityVerifier is retained by the CConnection instance.
virtual
IdentityVerifier
*
getIdentityVerifier
()
{
return
0
;}
// Methods to be overridden in a derived class
// 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
();
// initDone() is called when the connection is fully established
// and standard messages can be sent. This is called before the
// initial FramebufferUpdateRequest giving a derived class the
// chance to modify pixel format and settings. The derived class
// must also make sure it has provided a valid framebuffer before
// returning.
virtual
void
initDone
()
=
0
;
// resizeFramebuffer() is called whenever the framebuffer
// dimensions or the screen layout changes. A subclass must make
// sure the pixel buffer has been updated once this call returns.
virtual
void
resizeFramebuffer
();
// handleClipboardRequest() is called whenever the server requests
// the client to send over its clipboard data. It will only be
// called after the client has first announced a clipboard change
// via announceClipboard().
virtual
void
handleClipboardRequest
();
// handleClipboardAnnounce() is called to indicate a change in the
// clipboard on the server. Call requestClipboard() to access the
// actual data.
virtual
void
handleClipboardAnnounce
(
bool
available
);
// handleClipboardData() is called when the server has sent over
// the clipboard data as a result of a previous call to
// requestClipboard(). Note that this function might never be
// called if the clipboard data was no longer available when the
// server received the request.
virtual
void
handleClipboardData
(
const
char
*
data
);
// Other methods
// requestClipboard() will result in a request to the server to
// transfer its clipboard data. A call to handleClipboardData()
// will be made once the data is available.
virtual
void
requestClipboard
();
// announceClipboard() informs the server of changes to the
// clipboard on the client. The server may later request the
// clipboard data via handleClipboardRequest().
virtual
void
announceClipboard
(
bool
available
);
// sendClipboardData() transfers the clipboard data to the server
// and should be called whenever the server has requested the
// clipboard via handleClipboardRequest().
virtual
void
sendClipboardData
(
const
char
*
data
);
// refreshFramebuffer() forces a complete refresh of the entire
// framebuffer
void
refreshFramebuffer
();
// setPreferredEncoding()/getPreferredEncoding() adjusts which
// encoding is listed first as a hint to the server that it is the
// preferred one
void
setPreferredEncoding
(
int
encoding
);
int
getPreferredEncoding
();
// setCompressLevel()/setQualityLevel() controls the encoding hints
// sent to the server
void
setCompressLevel
(
int
level
);
void
setQualityLevel
(
int
level
);
// setPF() controls the pixel format requested from the server.
// server.pf() will automatically be adjusted once the new format
// is active.
void
setPF
(
const
PixelFormat
&
pf
);
CMsgReader
*
reader
()
{
return
reader_
;
}
CMsgWriter
*
writer
()
{
return
writer_
;
}
...
...
@@ -159,6 +228,13 @@ namespace rfb {
ModifiablePixelBuffer
*
getFramebuffer
()
{
return
framebuffer
;
}
protected
:
// Optional capabilities that a subclass is expected to set to true
// if supported
bool
supportsLocalCursor
;
bool
supportsDesktopResize
;
bool
supportsLEDState
;
private
:
// This is a default implementation of fences that automatically
// responds to requests, stating no support for synchronisation.
...
...
@@ -176,6 +252,9 @@ namespace rfb {
void
throwConnFailedException
();
void
securityCompleted
();
void
requestNewUpdate
();
void
updateEncodings
();
rdr
::
InStream
*
is
;
rdr
::
OutStream
*
os
;
CMsgReader
*
reader_
;
...
...
@@ -186,10 +265,28 @@ namespace rfb {
CharArray
serverName
;
bool
useProtocol3_3
;
bool
pendingPFChange
;
rfb
::
PixelFormat
pendingPF
;
int
preferredEncoding
;
int
compressLevel
;
int
qualityLevel
;
bool
formatChange
;
rfb
::
PixelFormat
nextPF
;
bool
encodingChange
;
bool
firstUpdate
;
bool
pendingUpdate
;
bool
continuousUpdates
;
bool
forceNonincremental
;
ModifiablePixelBuffer
*
framebuffer
;
DecodeManager
decoder
;
char
*
serverClipboard
;
bool
hasLocalClipboard
;
};
}
#endif
common/rfb/CMakeLists.txt
View file @
b149914d
...
...
@@ -11,9 +11,9 @@ set(RFB_SOURCES
CSecurityStack.cxx
CSecurityVeNCrypt.cxx
CSecurityVncAuth.cxx
ClientParams.cxx
ComparingUpdateTracker.cxx
Configuration.cxx
ConnParams.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
...
...
@@ -21,7 +21,6 @@ set(RFB_SOURCES
d3des.c
EncodeManager.cxx
Encoder.cxx
HTTPServer.cxx
HextileDecoder.cxx
HextileEncoder.cxx
JpegCompressor.cxx
...
...
@@ -44,6 +43,7 @@ set(RFB_SOURCES
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
ServerParams.cxx
Security.cxx
SecurityServer.cxx
SecurityClient.cxx
...
...
common/rfb/CMsgHandler.cxx
View file @
b149914d
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-201
1
Pierre Ossman for Cendio AB
* Copyright 2009-201
9
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
...
...
@@ -19,9 +19,12 @@
#include
<stdio.h>
#include
<rfb/Exception.h>
#include
<rfb/LogWriter.h>
#include
<rfb/CMsgHandler.h>
#include
<rfb/screenTypes.h>
static
rfb
::
LogWriter
vlog
(
"CMsgHandler"
);
using
namespace
rfb
;
CMsgHandler
::
CMsgHandler
()
...
...
@@ -34,50 +37,53 @@ CMsgHandler::~CMsgHandler()
void
CMsgHandler
::
setDesktopSize
(
int
width
,
int
height
)
{
cp
.
width
=
width
;
cp
.
height
=
height
;
server
.
setDimensions
(
width
,
height
);
}
void
CMsgHandler
::
setExtendedDesktopSize
(
unsigned
reason
,
unsigned
result
,
int
width
,
int
height
,
const
ScreenSet
&
layout
)
{
cp
.
supportsSetDesktopSize
=
true
;
server
.
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
;
server
.
setDimensions
(
width
,
height
,
layout
);
}
void
CMsgHandler
::
setPixelFormat
(
const
PixelFormat
&
pf
)
{
cp
.
setPF
(
pf
);
server
.
setPF
(
pf
);
}
void
CMsgHandler
::
setName
(
const
char
*
name
)
{
cp
.
setName
(
name
);
server
.
setName
(
name
);
}
void
CMsgHandler
::
fence
(
rdr
::
U32
flags
,
unsigned
len
,
const
char
data
[])
{
cp
.
supportsFence
=
true
;
server
.
supportsFence
=
true
;
}
void
CMsgHandler
::
endOfContinuousUpdates
()
{
cp
.
supportsContinuousUpdates
=
true
;
server
.
supportsContinuousUpdates
=
true
;
}
void
CMsgHandler
::
supportsQEMUKeyEvent
()
{
cp
.
supportsQEMUKeyEvent
=
true
;
server
.
supportsQEMUKeyEvent
=
true
;
}
void
CMsgHandler
::
serverInit
(
int
width
,
int
height
,
const
PixelFormat
&
pf
,
const
char
*
name
)
{
server
.
setDimensions
(
width
,
height
);
server
.
setPF
(
pf
);
server
.
setName
(
name
);
}
void
CMsgHandler
::
framebufferUpdateStart
()
...
...
@@ -90,5 +96,28 @@ void CMsgHandler::framebufferUpdateEnd()
void
CMsgHandler
::
setLEDState
(
unsigned
int
state
)
{
cp
.
setLEDState
(
state
);
server
.
setLEDState
(
state
);
}
void
CMsgHandler
::
handleClipboardCaps
(
rdr
::
U32
flags
,
const
rdr
::
U32
*
lengths
)
{
server
.
setClipboardCaps
(
flags
,
lengths
);
}
void
CMsgHandler
::
handleClipboardRequest
(
rdr
::
U32
flags
)
{
}
void
CMsgHandler
::
handleClipboardPeek
(
rdr
::
U32
flags
)
{
}
void
CMsgHandler
::
handleClipboardNotify
(
rdr
::
U32
flags
)
{
}
void
CMsgHandler
::
handleClipboardProvide
(
rdr
::
U32
flags
,
const
size_t
*
lengths
,
const
rdr
::
U8
*
const
*
data
)
{
}
common/rfb/CMsgHandler.h
View file @
b149914d
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-201
1
Pierre Ossman for Cendio AB
* Copyright 2009-201
9
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
...
...
@@ -26,7 +26,7 @@
#include
<rdr/types.h>
#include
<rfb/Pixel.h>
#include
<rfb/
Conn
Params.h>
#include
<rfb/
Server
Params.h>
#include
<rfb/Rect.h>
#include
<rfb/ScreenSet.h>
...
...
@@ -41,9 +41,10 @@ namespace rfb {
// 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.
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(),
// setName(), serverInit() and clipboardCaps methods, a derived class
// should call on to CMsgHandler's methods to set the members of "server"
// appropriately.
virtual
void
setDesktopSize
(
int
w
,
int
h
);
virtual
void
setExtendedDesktopSize
(
unsigned
reason
,
unsigned
result
,
...
...
@@ -56,7 +57,9 @@ namespace rfb {
virtual
void
fence
(
rdr
::
U32
flags
,
unsigned
len
,
const
char
data
[]);
virtual
void
endOfContinuousUpdates
();
virtual
void
supportsQEMUKeyEvent
();
virtual
void
serverInit
()
=
0
;
virtual
void
serverInit
(
int
width
,
int
height
,
const
PixelFormat
&
pf
,
const
char
*
name
)
=
0
;
virtual
void
readAndDecodeRect
(
const
Rect
&
r
,
int
encoding
,
ModifiablePixelBuffer
*
pb
)
=
0
;
...
...
@@ -68,11 +71,20 @@ namespace rfb {
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
serverCutText
(
const
char
*
str
)
=
0
;
virtual
void
setLEDState
(
unsigned
int
state
);
ConnParams
cp
;
virtual
void
handleClipboardCaps
(
rdr
::
U32
flags
,
const
rdr
::
U32
*
lengths
);
virtual
void
handleClipboardRequest
(
rdr
::
U32
flags
);
virtual
void
handleClipboardPeek
(
rdr
::
U32
flags
);
virtual
void
handleClipboardNotify
(
rdr
::
U32
flags
);
virtual
void
handleClipboardProvide
(
rdr
::
U32
flags
,
const
size_t
*
lengths
,
const
rdr
::
U8
*
const
*
data
);
ServerParams
server
;
};
}
#endif
common/rfb/CMsgReader.cxx
View file @
b149914d
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-201
7
Pierre Ossman for Cendio AB
* Copyright 2009-201
9
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
...
...
@@ -20,13 +20,21 @@
#include
<assert.h>
#include
<stdio.h>
#include
<rfb/msgTypes.h>
#include
<rdr/InStream.h>
#include
<rdr/ZlibInStream.h>
#include
<rfb/msgTypes.h>
#include
<rfb/clipboardTypes.h>
#include
<rfb/Exception.h>
#include
<rfb/LogWriter.h>
#include
<rfb/util.h>
#include
<rfb/CMsgHandler.h>
#include
<rfb/CMsgReader.h>
static
rfb
::
LogWriter
vlog
(
"CMsgReader"
);
static
rfb
::
IntParameter
maxCutText
(
"MaxCutText"
,
"Maximum permitted length of an incoming clipboard update"
,
256
*
1024
);
using
namespace
rfb
;
CMsgReader
::
CMsgReader
(
CMsgHandler
*
handler_
,
rdr
::
InStream
*
is_
)
...
...
@@ -43,13 +51,10 @@ 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
();
handler
->
serverInit
(
width
,
height
,
pf
,
name
.
buf
);
}
void
CMsgReader
::
readMsg
()
...
...
@@ -77,7 +82,7 @@ void CMsgReader::readMsg()
readEndOfContinuousUpdates
();
break
;
default:
fprintf
(
stderr
,
"unknown message type %d
\n
"
,
type
);
vlog
.
error
(
"unknown message type %d"
,
type
);
throw
Exception
(
"unknown message type"
);
}
}
else
{
...
...
@@ -100,6 +105,9 @@ void CMsgReader::readMsg()
case
pseudoEncodingCursorWithAlpha
:
readSetCursorWithAlpha
(
w
,
h
,
Point
(
x
,
y
));
break
;
case
pseudoEncodingVMwareCursor
:
readSetVMwareCursor
(
w
,
h
,
Point
(
x
,
y
));
break
;
case
pseudoEncodingDesktopName
:
readSetDesktopName
(
x
,
y
,
w
,
h
);
break
;
...
...
@@ -111,6 +119,10 @@ void CMsgReader::readMsg()
break
;
case
pseudoEncodingLEDState
:
readLEDState
();
break
;
case
pseudoEncodingVMwareLEDState
:
readVMwareLEDState
();
break
;
case
pseudoEncodingQEMUKeyEvent
:
handler
->
supportsQEMUKeyEvent
();
break
;
...
...
@@ -145,15 +157,116 @@ void CMsgReader::readServerCutText()
{
is
->
skip
(
3
);
rdr
::
U32
len
=
is
->
readU32
();
if
(
len
>
256
*
1024
)
{
if
(
len
&
0x80000000
)
{
rdr
::
S32
slen
=
len
;
slen
=
-
slen
;
readExtendedClipboard
(
slen
);
return
;
}
if
(
len
>
(
size_t
)
maxCutText
)
{
is
->
skip
(
len
);
fprintf
(
stderr
,
"cut text too long (%d bytes) - ignoring
\n
"
,
len
);
vlog
.
error
(
"cut text too long (%d bytes) - ignoring"
,
len
);
return
;
}
CharArray
ca
(
len
+
1
);
ca
.
buf
[
len
]
=
0
;
CharArray
ca
(
len
);
is
->
readBytes
(
ca
.
buf
,
len
);
handler
->
serverCutText
(
ca
.
buf
,
len
);
CharArray
filtered
(
convertLF
(
ca
.
buf
,
len
));
handler
->
serverCutText
(
filtered
.
buf
);
}
void
CMsgReader
::
readExtendedClipboard
(
rdr
::
S32
len
)
{
rdr
::
U32
flags
;
rdr
::
U32
action
;
if
(
len
<
4
)
throw
Exception
(
"Invalid extended clipboard message"
);
if
(
len
>
maxCutText
)
{
vlog
.
error
(
"Extended clipboard message too long (%d bytes) - ignoring"
,
len
);
is
->
skip
(
len
);
return
;
}
flags
=
is
->
readU32
();
action
=
flags
&
clipboardActionMask
;
if
(
action
&
clipboardCaps
)
{
int
i
;
size_t
num
;
rdr
::
U32
lengths
[
16
];
num
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
(
flags
&
(
1
<<
i
))
num
++
;
}
if
(
len
<
(
rdr
::
S32
)(
4
+
4
*
num
))
throw
Exception
(
"Invalid extended clipboard message"
);
num
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
(
flags
&
(
1
<<
i
))
lengths
[
num
++
]
=
is
->
readU32
();
}
handler
->
handleClipboardCaps
(
flags
,
lengths
);
}
else
if
(
action
==
clipboardProvide
)
{
rdr
::
ZlibInStream
zis
;
int
i
;
size_t
num
;
size_t
lengths
[
16
];
rdr
::
U8
*
buffers
[
16
];
zis
.
setUnderlying
(
is
,
len
-
4
);
num
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
(
!
(
flags
&
1
<<
i
))
continue
;
lengths
[
num
]
=
zis
.
readU32
();
if
(
lengths
[
num
]
>
(
size_t
)
maxCutText
)
{
vlog
.
error
(
"Extended clipboard data too long (%d bytes) - ignoring"
,
(
unsigned
)
lengths
[
num
]);
zis
.
skip
(
lengths
[
num
]);
flags
&=
~
(
1
<<
i
);
continue
;
}
buffers
[
num
]
=
new
rdr
::
U8
[
lengths
[
num
]];
zis
.
readBytes
(
buffers
[
num
],
lengths
[
num
]);
num
++
;
}
zis
.
removeUnderlying
();
handler
->
handleClipboardProvide
(
flags
,
lengths
,
buffers
);
num
=
0
;
for
(
i
=
0
;
i
<
16
;
i
++
)
{
if
(
!
(
flags
&
1
<<
i
))
continue
;
delete
[]
buffers
[
num
++
];
}
}
else
{
switch
(
action
)
{
case
clipboardRequest
:
handler
->
handleClipboardRequest
(
flags
);
break
;
case
clipboardPeek
:
handler
->
handleClipboardPeek
(
flags
);
break
;
case
clipboardNotify
:
handler
->
handleClipboardNotify
(
flags
);
break
;
default:
throw
Exception
(
"Invalid extended clipboard action"
);
}
}
}
void
CMsgReader
::
readFence
()
...
...
@@ -168,7 +281,7 @@ void CMsgReader::readFence()
len
=
is
->
readU8
();
if
(
len
>
sizeof
(
data
))
{
fprintf
(
stderr
,
"Ignoring fence with too large payload
\n
"
);
vlog
.
error
(
"Ignoring fence with too large payload"
);
is
->
skip
(
len
);
return
;
}
...
...
@@ -192,15 +305,16 @@ void CMsgReader::readFramebufferUpdate()
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
"
,
if
((
r
.
br
.
x
>
handler
->
server
.
width
())
||
(
r
.
br
.
y
>
handler
->
server
.
height
()))
{
vlog
.
error
(
"Rect too big: %dx%d at %d,%d exceeds %dx%d"
,
r
.
width
(),
r
.
height
(),
r
.
tl
.
x
,
r
.
tl
.
y
,
handler
->
cp
.
width
,
handler
->
cp
.
height
);
handler
->
server
.
width
()
,
handler
->
server
.
height
()
);
throw
Exception
(
"Rect too big"
);
}
if
(
r
.
is_empty
())
fprintf
(
stderr
,
"Warning:
zero size rect
\n
"
);
vlog
.
error
(
"
zero size rect"
);
handler
->
dataRect
(
r
,
encoding
);
}
...
...
@@ -210,6 +324,9 @@ void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
if
(
width
>
maxCursorSize
||
height
>
maxCursorSize
)
throw
Exception
(
"Too big cursor"
);
rdr
::
U8Array
rgba
(
width
*
height
*
4
);
if
(
width
*
height
>
0
)
{
rdr
::
U8
pr
,
pg
,
pb
;
rdr
::
U8
sr
,
sg
,
sb
;
int
data_len
=
((
width
+
7
)
/
8
)
*
height
;
...
...
@@ -218,10 +335,8 @@ void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
rdr
::
U8Array
mask
(
mask_len
);
int
x
,
y
;
rdr
::
U8
buf
[
width
*
height
*
4
];
rdr
::
U8
*
out
;
if
(
width
*
height
>
0
)
{
pr
=
is
->
readU8
();
pg
=
is
->
readU8
();
pb
=
is
->
readU8
();
...
...
@@ -232,10 +347,9 @@ void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
is
->
readBytes
(
data
.
buf
,
data_len
);
is
->
readBytes
(
mask
.
buf
,
mask_len
);
}
int
maskBytesPerRow
=
(
width
+
7
)
/
8
;
out
=
buf
;
out
=
rgba
.
buf
;
for
(
y
=
0
;
y
<
height
;
y
++
)
{
for
(
x
=
0
;
x
<
width
;
x
++
)
{
int
byte
=
y
*
maskBytesPerRow
+
x
/
8
;
...
...
@@ -259,8 +373,9 @@ void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
out
+=
4
;
}
}
}
handler
->
setCursor
(
width
,
height
,
hotspot
,
buf
);
handler
->
setCursor
(
width
,
height
,
hotspot
,
rgba
.
buf
);
}
void
CMsgReader
::
readSetCursor
(
int
width
,
int
height
,
const
Point
&
hotspot
)
...
...
@@ -268,13 +383,13 @@ 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
data_len
=
width
*
height
*
(
handler
->
server
.
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
Array
rgba
(
width
*
height
*
4
)
;
rdr
::
U8
*
in
;
rdr
::
U8
*
out
;
...
...
@@ -283,25 +398,25 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
int
maskBytesPerRow
=
(
width
+
7
)
/
8
;
in
=
data
.
buf
;
out
=
buf
;
out
=
rgba
.
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
);
handler
->
server
.
pf
().
rgbFromBuffer
(
out
,
in
,
1
);
if
(
mask
.
buf
[
byte
]
&
(
1
<<
bit
))
out
[
3
]
=
255
;
else
out
[
3
]
=
0
;
in
+=
handler
->
cp
.
pf
().
bpp
/
8
;
in
+=
handler
->
server
.
pf
().
bpp
/
8
;
out
+=
4
;
}
}
handler
->
setCursor
(
width
,
height
,
hotspot
,
buf
);
handler
->
setCursor
(
width
,
height
,
hotspot
,
rgba
.
buf
);
}
void
CMsgReader
::
readSetCursorWithAlpha
(
int
width
,
int
height
,
const
Point
&
hotspot
)
...
...
@@ -320,10 +435,10 @@ void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots
encoding
=
is
->
readS32
();
origPF
=
handler
->
cp
.
pf
();
handler
->
cp
.
setPF
(
rgbaPF
);
origPF
=
handler
->
server
.
pf
();
handler
->
server
.
setPF
(
rgbaPF
);
handler
->
readAndDecodeRect
(
pb
.
getRect
(),
encoding
,
&
pb
);
handler
->
cp
.
setPF
(
origPF
);
handler
->
server
.
setPF
(
origPF
);
// On-wire data has pre-multiplied alpha, but we store it
// non-pre-multiplied
...
...
@@ -350,12 +465,100 @@ void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots
pb
.
getBuffer
(
pb
.
getRect
(),
&
stride
));
}
void
CMsgReader
::
readSetVMwareCursor
(
int
width
,
int
height
,
const
Point
&
hotspot
)
{
if
(
width
>
maxCursorSize
||
height
>
maxCursorSize
)
throw
Exception
(
"Too big cursor"
);
rdr
::
U8
type
;
type
=
is
->
readU8
();
is
->
skip
(
1
);
if
(
type
==
0
)
{
int
len
=
width
*
height
*
(
handler
->
server
.
pf
().
bpp
/
8
);
rdr
::
U8Array
andMask
(
len
);
rdr
::
U8Array
xorMask
(
len
);
rdr
::
U8Array
data
(
width
*
height
*
4
);
rdr
::
U8
*
andIn
;
rdr
::
U8
*
xorIn
;
rdr
::
U8
*
out
;
int
Bpp
;
is
->
readBytes
(
andMask
.
buf
,
len
);
is
->
readBytes
(
xorMask
.
buf
,
len
);
andIn
=
andMask
.
buf
;
xorIn
=
xorMask
.
buf
;
out
=
data
.
buf
;
Bpp
=
handler
->
server
.
pf
().
bpp
/
8
;
for
(
int
y
=
0
;
y
<
height
;
y
++
)
{
for
(
int
x
=
0
;
x
<
width
;
x
++
)
{
Pixel
andPixel
,
xorPixel
;
andPixel
=
handler
->
server
.
pf
().
pixelFromBuffer
(
andIn
);
xorPixel
=
handler
->
server
.
pf
().
pixelFromBuffer
(
xorIn
);
andIn
+=
Bpp
;
xorIn
+=
Bpp
;
if
(
andPixel
==
0
)
{
rdr
::
U8
r
,
g
,
b
;
// Opaque pixel
handler
->
server
.
pf
().
rgbFromPixel
(
xorPixel
,
&
r
,
&
g
,
&
b
);
*
out
++
=
r
;
*
out
++
=
g
;
*
out
++
=
b
;
*
out
++
=
0xff
;
}
else
if
(
xorPixel
==
0
)
{
// Fully transparent pixel
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0
;
}
else
if
(
andPixel
==
xorPixel
)
{
// Inverted pixel
// We don't really support this, so just turn the pixel black
// FIXME: Do an outline like WinVNC does?
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0xff
;
}
else
{
// Partially transparent/inverted pixel
// We _really_ can't handle this, just make it black
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0
;
*
out
++
=
0xff
;
}
}
}
handler
->
setCursor
(
width
,
height
,
hotspot
,
data
.
buf
);
}
else
if
(
type
==
1
)
{
rdr
::
U8Array
data
(
width
*
height
*
4
);
// FIXME: Is alpha premultiplied?
is
->
readBytes
(
data
.
buf
,
width
*
height
*
4
);
handler
->
setCursor
(
width
,
height
,
hotspot
,
data
.
buf
);
}
else
{
throw
Exception
(
"Unknown cursor type"
);
}
}
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
"
);
vlog
.
error
(
"Ignoring DesktopName rect with non-zero position/size"
);
}
else
{
handler
->
setName
(
name
);
}
...
...
@@ -395,3 +598,15 @@ void CMsgReader::readLEDState()
handler
->
setLEDState
(
state
);
}
void
CMsgReader
::
readVMwareLEDState
()
{
rdr
::
U32
state
;
state
=
is
->
readU32
();
// As luck has it, this extension uses the same bit definitions,
// so no conversion required
handler
->
setLEDState
(
state
);
}
Prev
1
2
3
4
5
…
17
Next