Skip to content
Commits on Source (5)
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
......@@ -57,7 +57,7 @@ Build Requirements (Windows)
Build Requirements (Java)
=========================
-- Sun/Oracle JDK v5 or later or OpenJDK
-- Sun/Oracle JDK 1.7 or later or OpenJDK 7 or later
-- See "Building Java Support" below.
......
......@@ -21,10 +21,10 @@ include(CheckCSourceRuns)
include(CMakeMacroLibtoolFile)
project(tigervnc)
set(VERSION 1.8.0)
set(VERSION 1.9.0)
# The RC version must always be four comma-separated numbers
set(RCVERSION 1,8,0,0)
set(RCVERSION 1,9,0,0)
# Installation paths
set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin")
......@@ -68,6 +68,9 @@ 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")
# 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")
......@@ -122,8 +125,8 @@ endif()
# 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; 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; return 0;}" HAVE_ACTIVE_DESKTOP_L)
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
......
......@@ -19,7 +19,7 @@ JPEG codec.
Legal
=====
Incomplete and generally out of date copyright list:
Incomplete and generally out of date copyright list::
Copyright (C) 1999 AT&T Laboratories Cambridge
Copyright (C) 2002-2005 RealVNC Ltd.
......@@ -28,13 +28,13 @@ Incomplete and generally out of date copyright list:
Copyright (C) 2005-2006 Sun Microsystems, Inc.
Copyright (C) 2006 OCCAM Financial Technology
Copyright (C) 2000-2008 Constantin Kaplinsky
Copyright (C) 2004-2009 Peter Astrand for Cendio AB
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-2017 TigerVNC Team
Copyright (C) 2009-2018 TigerVNC Team
All Rights Reserved.
This software is distributed under the GNU General Public Licence as published
......@@ -50,7 +50,7 @@ All Platforms
All versions of TigerVNC contain the following programs:
vncviewer - the cross-platform TigerVNC Viewer, written using FLTK.
* vncviewer - the cross-platform TigerVNC Viewer, written using FLTK.
vncviewer connects to a VNC server and allows you to interact
with the remote desktop being displayed by the VNC server. The
VNC server can be running on a Windows or a Unix/Linux machine.
......@@ -61,7 +61,7 @@ Windows-Specific
The Windows version of TigerVNC contains the following programs:
winvnc - the TigerVNC Server for Windows. winvnc allows a Windows desktop to
* winvnc - the TigerVNC Server for Windows. winvnc allows a Windows desktop to
be accessed remotely using a VNC viewer.
winvnc may not work if the Fast User Switching or Remote Desktop features are
......@@ -73,23 +73,23 @@ Unix/Linux-Specific (not Mac)
The Unix/Linux version of TigerVNC contains the following programs:
Xvnc - the TigerVNC Server for Unix. Xvnc is both a VNC server and an X
* Xvnc - the TigerVNC Server for Unix. Xvnc is both a VNC server and an X
server with a "virtual" framebuffer. You should normally use the
vncserver script to start Xvnc.
vncserver - a wrapper script which makes starting Xvnc more convenient.
* vncserver - a wrapper script which makes starting Xvnc more convenient.
vncserver requires Perl.
vncpasswd - a program which allows you to change the VNC password used to
* vncpasswd - a program which allows you to change the VNC password used to
access your VNC server sessions (assuming that VNC authentication
is being used.) The vncserver script will automatically launch
this program if it detects that VNC authentication is in use and
a VNC password has not yet been configured.
vncconfig - a program which is used to configure and control a running
* vncconfig - a program which is used to configure and control a running
instance of Xvnc.
x0vncserver - an inefficient VNC server which continuously polls any X
* x0vncserver - an inefficient VNC server which continuously polls any X
display, allowing it to be controlled via VNC. It is intended
mainly as a demonstration of a simple VNC server.
......
......@@ -87,4 +87,4 @@ endif() #UNIX
#
install(FILES ${CMAKE_SOURCE_DIR}/LICENCE.TXT DESTINATION ${DOC_DIR})
install(FILES ${CMAKE_SOURCE_DIR}/README.txt DESTINATION ${DOC_DIR})
install(FILES ${CMAKE_SOURCE_DIR}/README.rst DESTINATION ${DOC_DIR})
macro(libtool_create_control_file _target)
get_target_property(_target_location ${_target} LOCATION)
get_target_property(_target_type ${_target} TYPE)
message("-- Creating static libtool control file for target ${_target}")
......@@ -44,8 +43,7 @@ macro(libtool_create_control_file _target)
else()
# No shared library extension matched. Check whether target is a CMake
# target.
get_target_property(_ltp ${library} TYPE)
if(_ltp OR ${library} STREQUAL "general")
if(TARGET ${library})
# Target is a CMake target, so ignore (CMake targets are static
# libs in TigerVNC.)
elseif(${library} STREQUAL "-Wl,-Bstatic")
......@@ -113,7 +111,7 @@ macro(libtool_create_control_file _target)
endforeach()
# Write the libtool control file for the static library
get_filename_component(_lname ${_target_location} NAME_WE)
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")
......@@ -142,6 +140,6 @@ macro(libtool_create_control_file _target)
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 ${_target_location} "${CMAKE_CURRENT_BINARY_DIR}/.libs/${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX}")
"${CMAKE_COMMAND}" -E create_symlink ../${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX} "${CMAKE_CURRENT_BINARY_DIR}/.libs/${_lname}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endmacro()
......@@ -91,7 +91,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 -lbz2 -lXrender -lXext -lXinerama -Wl,-Bdynamic")
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")
......@@ -109,6 +109,9 @@ if(BUILD_STATIC)
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()
......
include_directories(${CMAKE_SOURCE_DIR}/common)
add_library(network STATIC
set(NETWORK_SOURCES
Socket.cxx
TcpSocket.cxx)
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()
......
/* 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;
}
......@@ -30,51 +30,40 @@
namespace network {
void initSockets();
bool isSocketListening(int sock);
class Socket {
public:
Socket(int fd)
: instream(new rdr::FdInStream(fd)),
outstream(new rdr::FdOutStream(fd)),
ownStreams(true), isShutdown_(false),
queryConnection(false) {}
virtual ~Socket() {
if (ownStreams) {
delete instream;
delete outstream;
}
}
Socket(int fd);
virtual ~Socket();
rdr::FdInStream &inStream() {return *instream;}
rdr::FdOutStream &outStream() {return *outstream;}
int getFd() {return outstream->getFd();}
// if shutdown() is overridden then the override MUST call on to here
virtual void shutdown() {isShutdown_ = true;}
bool isShutdown() const {return isShutdown_;}
void shutdown();
bool isShutdown() const;
// information about this end of the socket
virtual int getMyPort() = 0;
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 int getPeerPort() = 0;
virtual char* getPeerEndpoint() = 0; // <address>::<port>
// Is the remote end on the same machine?
virtual bool sameMachine() = 0;
// Was there a "?" in the ConnectionFilter used to accept this Socket?
void setRequiresQuery() {queryConnection = true;}
bool requiresQuery() const {return queryConnection;}
void setRequiresQuery();
bool requiresQuery() const;
protected:
Socket() : instream(0), outstream(0), ownStreams(false),
isShutdown_(false), queryConnection(false) {}
Socket(rdr::FdInStream* i, rdr::FdOutStream* o, bool own)
: instream(i), outstream(o), ownStreams(own),
isShutdown_(false), queryConnection(false) {}
Socket();
void setFd(int fd);
private:
rdr::FdInStream* instream;
rdr::FdOutStream* outstream;
bool ownStreams;
bool isShutdown_;
bool queryConnection;
};
......@@ -82,24 +71,37 @@ namespace network {
class ConnectionFilter {
public:
virtual bool verifyConnection(Socket* s) = 0;
virtual ~ConnectionFilter() {}
};
class SocketListener {
public:
SocketListener() : fd(0), filter(0) {}
virtual ~SocketListener() {}
SocketListener(int fd);
virtual ~SocketListener();
// shutdown() stops the socket from accepting further connections
virtual void shutdown() = 0;
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.
virtual Socket* accept() = 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;
......
......@@ -28,21 +28,17 @@
#else
#define errorNumber errno
#define closesocket close
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <network/TcpSocket.h>
#include <rfb/util.h>
#include <rfb/LogWriter.h>
#include <rfb/Configuration.h>
......@@ -99,40 +95,35 @@ int network::findFreeTcpPort (void)
return ntohs(addr.sin_port);
}
int network::getSockPort(int sock)
{
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);
if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
return 0;
// -=- Socket initialisation
static bool socketsInitialised = false;
static void 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;
switch (sa.u.sa.sa_family) {
case AF_INET6:
return ntohs(sa.u.sin6.sin6_port);
default:
return ntohs(sa.u.sin.sin_port);
}
}
// -=- TcpSocket
TcpSocket::TcpSocket(int sock, bool close)
: Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
TcpSocket::TcpSocket(int sock) : Socket(sock)
{
// Disable Nagle's algorithm, to reduce latency
enableNagles(false);
}
TcpSocket::TcpSocket(const char *host, int port)
: closeFd(true)
{
int sock, err, result;
struct addrinfo *ai, *current, hints;
// - Create a socket
initSockets();
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
......@@ -214,27 +205,11 @@ TcpSocket::TcpSocket(const char *host, int port)
throw SocketException("unable connect to socket", err);
}
#ifndef WIN32
// - By default, close the socket on exec()
fcntl(sock, F_SETFD, FD_CLOEXEC);
#endif
// Take proper ownership of the socket
setFd(sock);
// Disable Nagle's algorithm, to reduce latency
enableNagles(sock, false);
// Create the input and output streams
instream = new FdInStream(sock);
outstream = new FdOutStream(sock);
ownStreams = true;
}
TcpSocket::~TcpSocket() {
if (closeFd)
closesocket(getFd());
}
int TcpSocket::getMyPort() {
return getSockPort(getFd());
enableNagles(false);
}
char* TcpSocket::getPeerAddress() {
......@@ -281,25 +256,20 @@ char* TcpSocket::getPeerAddress() {
return rfb::strDup("");
}
int TcpSocket::getPeerPort() {
char* TcpSocket::getPeerEndpoint() {
rfb::CharArray address; address.buf = getPeerAddress();
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);
int port;
getpeername(getFd(), &sa.u.sa, &sa_size);
switch (sa.u.sa.sa_family) {
case AF_INET6:
return ntohs(sa.u.sin6.sin6_port);
case AF_INET:
return ntohs(sa.u.sin.sin_port);
default:
return 0;
}
}
char* TcpSocket::getPeerEndpoint() {
rfb::CharArray address; address.buf = getPeerAddress();
int port = getPeerPort();
if (sa.u.sa.sa_family == AF_INET6)
port = ntohs(sa.u.sin6.sin6_port);
else if (sa.u.sa.sa_family == AF_INET)
port = ntohs(sa.u.sin.sin_port);
else
port = 0;
int buflen = strlen(address.buf) + 32;
char* buffer = new char[buflen];
......@@ -307,40 +277,9 @@ char* TcpSocket::getPeerEndpoint() {
return buffer;
}
bool TcpSocket::sameMachine() {
vnc_sockaddr_t peeraddr, myaddr;
socklen_t addrlen;
addrlen = sizeof(peeraddr);
if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
throw SocketException ("unable to get peer address", errorNumber);
addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
throw SocketException ("unable to get my address", errorNumber);
if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
return false;
if (peeraddr.u.sa.sa_family == AF_INET6)
return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
&myaddr.u.sin6.sin6_addr);
if (peeraddr.u.sa.sa_family == AF_INET)
return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
// No idea what this is. Assume we're on different machines.
return false;
}
void TcpSocket::shutdown()
{
Socket::shutdown();
::shutdown(getFd(), 2);
}
bool TcpSocket::enableNagles(int sock, bool enable) {
bool TcpSocket::enableNagles(bool enable) {
int one = enable ? 0 : 1;
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
if (setsockopt(getFd(), IPPROTO_TCP, TCP_NODELAY,
(char *)&one, sizeof(one)) < 0) {
int e = errorNumber;
vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
......@@ -349,45 +288,19 @@ bool TcpSocket::enableNagles(int sock, bool enable) {
return true;
}
bool TcpSocket::cork(int sock, bool enable) {
bool TcpSocket::cork(bool enable) {
#ifndef TCP_CORK
return false;
#else
int one = enable ? 1 : 0;
if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
if (setsockopt(getFd(), IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
return false;
return true;
#endif
}
bool TcpSocket::isListening(int sock)
TcpListener::TcpListener(int sock) : SocketListener(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;
}
int TcpSocket::getSockPort(int sock)
{
vnc_sockaddr_t sa;
socklen_t sa_size = sizeof(sa);
if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
return 0;
switch (sa.u.sa.sa_family) {
case AF_INET6:
return ntohs(sa.u.sin6.sin6_port);
default:
return ntohs(sa.u.sin.sin_port);
}
}
TcpListener::TcpListener(int sock)
{
fd = sock;
}
TcpListener::TcpListener(const struct sockaddr *listenaddr,
......@@ -397,8 +310,6 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
vnc_sockaddr_t sa;
int sock;
initSockets();
if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
throw SocketException("unable to create listening socket", errorNumber);
......@@ -436,53 +347,11 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
throw SocketException("failed to bind socket", e);
}
// - 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);
listen(sock);
}
fd = sock;
}
TcpListener::~TcpListener() {
closesocket(fd);
}
void TcpListener::shutdown()
{
#ifdef WIN32
closesocket(getFd());
#else
::shutdown(getFd(), 2);
#endif
}
Socket*
TcpListener::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);
#ifndef WIN32
// - By default, close the socket on exec()
fcntl(new_sock, F_SETFD, FD_CLOEXEC);
#endif
// Disable Nagle's algorithm, to reduce latency
TcpSocket::enableNagles(new_sock, false);
// Create the socket object & check connection is allowed
TcpSocket* s = new TcpSocket(new_sock);
if (filter && !filter->verifyConnection(s)) {
delete s;
return 0;
}
return s;
Socket* TcpListener::createSocket(int fd) {
return new TcpSocket(fd);
}
void TcpListener::getMyAddresses(std::list<char*>* result) {
......@@ -528,11 +397,11 @@ void TcpListener::getMyAddresses(std::list<char*>* result) {
}
int TcpListener::getMyPort() {
return TcpSocket::getSockPort(getFd());
return getSockPort(getFd());
}
void network::createLocalTcpListeners(std::list<TcpListener*> *listeners,
void network::createLocalTcpListeners(std::list<SocketListener*> *listeners,
int port)
{
struct addrinfo ai[2];
......@@ -562,7 +431,7 @@ void network::createLocalTcpListeners(std::list<TcpListener*> *listeners,
createTcpListeners(listeners, ai);
}
void network::createTcpListeners(std::list<TcpListener*> *listeners,
void network::createTcpListeners(std::list<SocketListener*> *listeners,
const char *addr,
int port)
{
......@@ -594,11 +463,11 @@ void network::createTcpListeners(std::list<TcpListener*> *listeners,
}
}
void network::createTcpListeners(std::list<TcpListener*> *listeners,
void network::createTcpListeners(std::list<SocketListener*> *listeners,
const struct addrinfo *ai)
{
const struct addrinfo *current;
std::list<TcpListener*> new_listeners;
std::list<SocketListener*> new_listeners;
initSockets();
......
......@@ -48,48 +48,41 @@ namespace network {
/* Tunnelling support. */
int findFreeTcpPort (void);
int getSockPort(int sock);
class TcpSocket : public Socket {
public:
TcpSocket(int sock, bool close=true);
TcpSocket(int sock);
TcpSocket(const char *name, int port);
virtual ~TcpSocket();
virtual int getMyPort();
virtual char* getPeerAddress();
virtual int getPeerPort();
virtual char* getPeerEndpoint();
virtual bool sameMachine();
virtual void shutdown();
virtual bool cork(bool enable);
static bool enableNagles(int sock, bool enable);
static bool cork(int sock, bool enable);
static bool isListening(int sock);
static int getSockPort(int sock);
private:
bool closeFd;
protected:
bool enableNagles(bool enable);
};
class TcpListener : public SocketListener {
public:
TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen);
TcpListener(int sock);
virtual ~TcpListener();
virtual void shutdown();
virtual Socket* accept();
virtual int getMyPort();
static void getMyAddresses(std::list<char*>* result);
int getMyPort();
protected:
virtual Socket* createSocket(int fd);
};
void createLocalTcpListeners(std::list<TcpListener*> *listeners,
void createLocalTcpListeners(std::list<SocketListener*> *listeners,
int port);
void createTcpListeners(std::list<TcpListener*> *listeners,
void createTcpListeners(std::list<SocketListener*> *listeners,
const char *addr,
int port);
void createTcpListeners(std::list<TcpListener*> *listeners,
void createTcpListeners(std::list<SocketListener*> *listeners,
const struct addrinfo *ai);
typedef struct vnc_sockaddr {
......
/* 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;
}
/* 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__
......@@ -49,12 +49,8 @@ Mutex::~Mutex()
DeleteCriticalSection((CRITICAL_SECTION*)systemMutex);
delete (CRITICAL_SECTION*)systemMutex;
#else
int ret;
ret = pthread_mutex_destroy((pthread_mutex_t*)systemMutex);
pthread_mutex_destroy((pthread_mutex_t*)systemMutex);
delete (pthread_mutex_t*)systemMutex;
if (ret != 0)
throw rdr::SystemException("Failed to destroy mutex", ret);
#endif
}
......@@ -106,12 +102,8 @@ Condition::~Condition()
#ifdef WIN32
delete (CONDITION_VARIABLE*)systemCondition;
#else
int ret;
ret = pthread_cond_destroy((pthread_cond_t*)systemCondition);
pthread_cond_destroy((pthread_cond_t*)systemCondition);
delete (pthread_cond_t*)systemCondition;
if (ret != 0)
throw rdr::SystemException("Failed to destroy condition variable", ret);
#endif
}
......
......@@ -43,15 +43,11 @@ namespace rdr {
};
struct TimedOut : public Exception {
TimedOut(const char* s="Timed out") : Exception("%s", s) {}
TimedOut() : Exception("Timed out") {}
};
struct EndOfStream : public Exception {
EndOfStream(const char* s="End of stream") : Exception("%s", s) {}
};
struct FrameException : public Exception {
FrameException(const char* s="Frame exception") : Exception("%s", s) {}
EndOfStream() : Exception("End of stream") {}
};
}
......
......@@ -26,13 +26,13 @@
#include <sys/time.h>
#ifdef _WIN32
#include <winsock2.h>
#define read(s,b,l) recv(s,(char*)b,l,0)
#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
......@@ -165,9 +165,9 @@ int FdInStream::overrun(int itemSize, int nItems, bool wait)
// 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 read() unless select() indicates that the fd is readable -
// 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 read()
// has to cope with the annoying possibility of both select() and recv()
// returning EINTR.
//
......@@ -207,7 +207,7 @@ int FdInStream::readWithTimeoutOrCallback(void* buf, int len, bool wait)
}
do {
n = ::read(fd, buf, len);
n = ::recv(fd, (char*)buf, len, 0);
} while (n < 0 && errno == EINTR);
if (n < 0) throw SystemException("read",errno);
......
......@@ -30,6 +30,7 @@ namespace rdr {
class FdInStreamBlockCallback {
public:
virtual void blockCallback() = 0;
virtual ~FdInStreamBlockCallback() {}
};
class FdInStream : public InStream {
......
/* 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
......@@ -26,7 +27,6 @@
#include <errno.h>
#ifdef _WIN32
#include <winsock2.h>
#define write(s,b,l) send(s,(const char*)b,l,0)
#undef errno
#define errno WSAGetLastError()
#include <os/winerrno.h>
......@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#endif
/* Old systems have select() in sys/time.h */
......@@ -159,10 +160,10 @@ int FdOutStream::overrun(int itemSize, int 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 write() unless select() indicates that
// 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 write() returning EINTR.
// select() and send() returning EINTR.
//
int FdOutStream::writeWithTimeout(const void* data, int length, int timeoutms)
......@@ -193,7 +194,14 @@ int FdOutStream::writeWithTimeout(const void* data, int length, int timeoutms)
return 0;
do {
n = ::write(fd, data, length);
// 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)
......
......@@ -70,12 +70,12 @@ int FileInStream::overrun(int itemSize, int nItems, bool wait)
while (end < b + itemSize) {
size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file);
if (n < 1) {
if (n < 0 || ferror(file))
if (n == 0) {
if (ferror(file))
throw SystemException("fread", errno);
if (feof(file))
throw EndOfStream();
if (n == 0) { return 0; }
return 0;
}
end += b + sizeof(b) - end;
}
......