@@ -1,8 +1,15 @@ | |||
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() |
@@ -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; | |||
} |
@@ -30,52 +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_;} | |||
virtual bool cork(bool enable) = 0; | |||
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; | |||
}; | |||
@@ -88,20 +76,32 @@ namespace network { | |||
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); | |||
@@ -360,34 +299,8 @@ bool TcpSocket::cork(bool enable) { | |||
#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); | |||
} | |||
fd = sock; | |||
listen(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 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 { |
@@ -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; | |||
} |
@@ -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__ |
@@ -338,7 +338,7 @@ bool | |||
IntParameter::setParam(const char* v) { | |||
if (immutable) return true; | |||
vlog.debug("set %s(Int) to %s", getName(), v); | |||
int i = atoi(v); | |||
int i = strtol(v, NULL, 0); | |||
if (i < minValue || i > maxValue) | |||
return false; | |||
value = i; |
@@ -31,6 +31,7 @@ | |||
#include <rfb/Configuration.h> | |||
#include <rfb/Timer.h> | |||
#include <network/TcpSocket.h> | |||
#include <network/UnixSocket.h> | |||
#include <vncconfig/QueryConnectDialog.h> | |||
@@ -58,6 +59,8 @@ IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of " | |||
"CPU time to be consumed", 35); | |||
StringParameter displayname("display", "The X display", ""); | |||
IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900); | |||
StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", ""); | |||
IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600); | |||
IntParameter queryConnectTimeout("QueryConnectTimeout", | |||
"Number of seconds to show the Accept Connection dialog before " | |||
"rejecting the connection", | |||
@@ -291,7 +294,7 @@ int main(int argc, char** argv) | |||
signal(SIGINT, CleanupSignalHandler); | |||
signal(SIGTERM, CleanupSignalHandler); | |||
std::list<TcpListener*> listeners; | |||
std::list<SocketListener*> listeners; | |||
try { | |||
TXWindow::init(dpy,"x0vncserver"); | |||
@@ -307,13 +310,18 @@ int main(int argc, char** argv) | |||
QueryConnHandler qcHandler(dpy, &server); | |||
server.setQueryConnectionHandler(&qcHandler); | |||
createTcpListeners(&listeners, 0, (int)rfbport); | |||
vlog.info("Listening on port %d", (int)rfbport); | |||
if (rfbunixpath.getValueStr()[0] != '\0') { | |||
listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode)); | |||
vlog.info("Listening on %s (mode %04o)", (const char*)rfbunixpath, (int)rfbunixmode); | |||
} else { | |||
createTcpListeners(&listeners, 0, (int)rfbport); | |||
vlog.info("Listening on port %d", (int)rfbport); | |||
} | |||
const char *hostsData = hostsFile.getData(); | |||
FileTcpFilter fileTcpFilter(hostsData); | |||
if (strlen(hostsData) != 0) | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
(*i)->setFilter(&fileTcpFilter); | |||
@@ -335,7 +343,7 @@ int main(int argc, char** argv) | |||
FD_ZERO(&wfds); | |||
FD_SET(ConnectionNumber(dpy), &rfds); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i)->getFd(), &rfds); | |||
@@ -387,7 +395,7 @@ int main(int argc, char** argv) | |||
} | |||
// Accept new VNC connections | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) { | |||
if (FD_ISSET((*i)->getFd(), &rfds)) { |
@@ -66,6 +66,15 @@ Use IPv4 for incoming and outgoing connections. Default is on. | |||
Use IPv6 for incoming and outgoing connections. Default is on. | |||
. | |||
.TP | |||
.B \-rfbunixpath \fIpath\fP | |||
Specifies the path of a Unix domain socket on which x0vncserver listens for | |||
connections from viewers, instead of listening on a TCP port. | |||
. | |||
.TP | |||
.B \-rfbunixmode \fImode\fP | |||
Specifies the mode of the Unix domain socket. The default is 0600. | |||
. | |||
.TP | |||
.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP | |||
Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP, | |||
\fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning |
@@ -192,14 +192,14 @@ void vncListParams(int width, int nameWidth) | |||
int vncGetSocketPort(int fd) | |||
{ | |||
return network::TcpSocket::getSockPort(fd); | |||
return network::getSockPort(fd); | |||
} | |||
int vncIsTCPPortUsed(int port) | |||
{ | |||
try { | |||
// Attempt to create TCPListeners on that port. | |||
std::list<network::TcpListener*> dummy; | |||
std::list<network::SocketListener*> dummy; | |||
network::createTcpListeners (&dummy, 0, port); | |||
while (!dummy.empty()) { | |||
delete dummy.back(); |
@@ -32,7 +32,7 @@ | |||
#include <fcntl.h> | |||
#include <sys/utsname.h> | |||
#include <network/TcpSocket.h> | |||
#include <network/Socket.h> | |||
#include <rfb/Exception.h> | |||
#include <rfb/VNCServerST.h> | |||
#include <rfb/HTTPServer.h> | |||
@@ -107,8 +107,8 @@ public: | |||
XserverDesktop::XserverDesktop(int screenIndex_, | |||
std::list<network::TcpListener*> listeners_, | |||
std::list<network::TcpListener*> httpListeners_, | |||
std::list<network::SocketListener*> listeners_, | |||
std::list<network::SocketListener*> httpListeners_, | |||
const char* name, const rfb::PixelFormat &pf, | |||
int width, int height, | |||
void* fbptr, int stride) | |||
@@ -127,13 +127,13 @@ XserverDesktop::XserverDesktop(int screenIndex_, | |||
if (!httpListeners.empty ()) | |||
httpServer = new FileHTTPServer(this); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) { | |||
vncSetNotifyFd((*i)->getFd(), screenIndex, true, false); | |||
} | |||
for (std::list<TcpListener*>::iterator i = httpListeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = httpListeners.begin(); | |||
i != httpListeners.end(); | |||
i++) { | |||
vncSetNotifyFd((*i)->getFd(), screenIndex, true, false); | |||
@@ -386,10 +386,10 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write) | |||
} | |||
bool XserverDesktop::handleListenerEvent(int fd, | |||
std::list<TcpListener*>* sockets, | |||
std::list<SocketListener*>* sockets, | |||
SocketServer* sockserv) | |||
{ | |||
std::list<TcpListener*>::iterator i; | |||
std::list<SocketListener*>::iterator i; | |||
for (i = sockets->begin(); i != sockets->end(); i++) { | |||
if ((*i)->getFd() == fd) |
@@ -44,7 +44,7 @@ namespace rfb { | |||
class VNCServerST; | |||
} | |||
namespace network { class TcpListener; class Socket; class SocketServer; } | |||
namespace network { class SocketListener; class Socket; class SocketServer; } | |||
class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, | |||
public rdr::Substitutor, | |||
@@ -53,8 +53,8 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, | |||
public: | |||
XserverDesktop(int screenIndex, | |||
std::list<network::TcpListener*> listeners_, | |||
std::list<network::TcpListener*> httpListeners_, | |||
std::list<network::SocketListener*> listeners_, | |||
std::list<network::SocketListener*> httpListeners_, | |||
const char* name, const rfb::PixelFormat &pf, | |||
int width, int height, void* fbptr, int stride); | |||
virtual ~XserverDesktop(); | |||
@@ -109,7 +109,7 @@ public: | |||
protected: | |||
bool handleListenerEvent(int fd, | |||
std::list<network::TcpListener*>* sockets, | |||
std::list<network::SocketListener*>* sockets, | |||
network::SocketServer* sockserv); | |||
bool handleSocketEvent(int fd, | |||
network::SocketServer* sockserv, | |||
@@ -122,8 +122,8 @@ private: | |||
int screenIndex; | |||
rfb::VNCServerST* server; | |||
rfb::HTTPServer* httpServer; | |||
std::list<network::TcpListener*> listeners; | |||
std::list<network::TcpListener*> httpListeners; | |||
std::list<network::SocketListener*> listeners; | |||
std::list<network::SocketListener*> httpListeners; | |||
bool directFbptr; | |||
uint32_t queryConnectId; |
@@ -91,6 +91,15 @@ Use IPv4 for incoming and outgoing connections. Default is on. | |||
Use IPv6 for incoming and outgoing connections. Default is on. | |||
. | |||
.TP | |||
.B \-rfbunixpath \fIpath\fP | |||
Specifies the path of a Unix domain socket on which Xvnc listens for | |||
connections from viewers, instead of listening on a TCP port. | |||
. | |||
.TP | |||
.B \-rfbunixmode \fImode\fP | |||
Specifies the mode of the Unix domain socket. The default is 0600. | |||
. | |||
.TP | |||
.B \-rfbwait \fItime\fP, \-ClientWaitTimeMillis \fItime\fP | |||
Time in milliseconds to wait for a viewer which is blocking the server. This is | |||
necessary because the server is single-threaded and sometimes blocks until the |
@@ -585,6 +585,7 @@ static int SProcVncExtDispatch(ClientPtr client) | |||
static void vncResetProc(ExtensionEntry* extEntry) | |||
{ | |||
vncExtensionClose(); | |||
} | |||
static void vncClientStateChange(CallbackListPtr * l, void * d, void * p) |
@@ -34,6 +34,7 @@ | |||
#include <rfb/Region.h> | |||
#include <rfb/ledStates.h> | |||
#include <network/TcpSocket.h> | |||
#include <network/UnixSocket.h> | |||
#include "XserverDesktop.h" | |||
#include "vncExtInit.h" | |||
@@ -79,6 +80,8 @@ rfb::IntParameter httpPort("httpPort", "TCP port to listen for HTTP",0); | |||
rfb::AliasParameter rfbwait("rfbwait", "Alias for ClientWaitTimeMillis", | |||
&rfb::Server::clientWaitTimeMillis); | |||
rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0); | |||
rfb::StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", ""); | |||
rfb::IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600); | |||
rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11"); | |||
rfb::BoolParameter localhostOnly("localhost", | |||
"Only allow connections from localhost", | |||
@@ -173,14 +176,29 @@ void vncExtensionInit(void) | |||
for (int scr = 0; scr < vncGetScreenCount(); scr++) { | |||
if (!desktop[scr]) { | |||
std::list<network::TcpListener*> listeners; | |||
std::list<network::TcpListener*> httpListeners; | |||
std::list<network::SocketListener*> listeners; | |||
std::list<network::SocketListener*> httpListeners; | |||
if (scr == 0 && vncInetdSock != -1) { | |||
if (network::TcpSocket::isListening(vncInetdSock)) | |||
if (network::isSocketListening(vncInetdSock)) | |||
{ | |||
listeners.push_back(new network::TcpListener(vncInetdSock)); | |||
vlog.info("inetd wait"); | |||
} | |||
} else if (rfbunixpath.getValueStr()[0] != '\0') { | |||
char path[PATH_MAX]; | |||
int mode = (int)rfbunixmode; | |||
if (scr == 0) | |||
strncpy(path, rfbunixpath, sizeof(path)); | |||
else | |||
snprintf(path, sizeof(path), "%s.%d", | |||
rfbunixpath.getValueStr(), scr); | |||
path[sizeof(path)-1] = '\0'; | |||
listeners.push_back(new network::UnixListener(path, mode)); | |||
vlog.info("Listening for VNC connections on %s (mode %04o)", | |||
path, mode); | |||
} else { | |||
const char *addr = interface; | |||
int port = rfbport; | |||
@@ -244,6 +262,18 @@ void vncExtensionInit(void) | |||
vncRegisterBlockHandlers(); | |||
} | |||
void vncExtensionClose(void) | |||
{ | |||
try { | |||
for (int scr = 0; scr < vncGetScreenCount(); scr++) { | |||
delete desktop[scr]; | |||
desktop[scr] = NULL; | |||
} | |||
} catch (rdr::Exception& e) { | |||
vncFatalError("vncExtInit: %s",e.str()); | |||
} | |||
} | |||
void vncHandleSocketEvent(int fd, int scrIdx, int read, int write) | |||
{ | |||
desktop[scrIdx]->handleSocketEvent(fd, read, write); |
@@ -48,6 +48,7 @@ extern int vncFbstride[]; | |||
extern int vncInetdSock; | |||
void vncExtensionInit(void); | |||
void vncExtensionClose(void); | |||
void vncHandleSocketEvent(int fd, int scrIdx, int read, int write); | |||
void vncCallBlockHandlers(int* timeout); |
@@ -39,6 +39,9 @@ | |||
#include <rdr/MemInStream.h> | |||
#include <rdr/MemOutStream.h> | |||
#include <network/TcpSocket.h> | |||
#ifndef WIN32 | |||
#include <network/UnixSocket.h> | |||
#endif | |||
#include <FL/Fl.H> | |||
#include <FL/fl_ask.H> | |||
@@ -106,10 +109,19 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) | |||
if(sock == NULL) { | |||
try { | |||
getHostAndPort(vncServerName, &serverHost, &serverPort); | |||
#ifndef WIN32 | |||
if (strchr(vncServerName, '/') != NULL) { | |||
sock = new network::UnixSocket(vncServerName); | |||
serverHost = sock->getPeerAddress(); | |||
vlog.info(_("connected to socket %s"), serverHost); | |||
} else | |||
#endif | |||
{ | |||
getHostAndPort(vncServerName, &serverHost, &serverPort); | |||
sock = new network::TcpSocket(serverHost, serverPort); | |||
vlog.info(_("connected to host %s port %d"), serverHost, serverPort); | |||
sock = new network::TcpSocket(serverHost, serverPort); | |||
vlog.info(_("connected to host %s port %d"), serverHost, serverPort); | |||
} | |||
} catch (rdr::Exception& e) { | |||
vlog.error("%s", e.str()); | |||
if (alertOnFatalError) |
@@ -376,6 +376,18 @@ potentiallyLoadConfigurationFile(char *vncServerName) | |||
(strchr(vncServerName, '\\')) != NULL); | |||
if (hasPathSeparator) { | |||
#ifndef WIN32 | |||
struct stat sb; | |||
// This might be a UNIX socket, we need to check | |||
if (stat(vncServerName, &sb) == -1) { | |||
// Some access problem; let loadViewerParameters() deal with it... | |||
} else { | |||
if ((sb.st_mode & S_IFMT) == S_IFSOCK) | |||
return; | |||
} | |||
#endif | |||
try { | |||
const char* newServerName; | |||
newServerName = loadViewerParameters(vncServerName); | |||
@@ -573,7 +585,7 @@ int main(int argc, char** argv) | |||
#endif | |||
if (listenMode) { | |||
std::list<TcpListener*> listeners; | |||
std::list<SocketListener*> listeners; | |||
try { | |||
int port = 5500; | |||
if (isdigit(vncServerName[0])) | |||
@@ -587,7 +599,7 @@ int main(int argc, char** argv) | |||
while (sock == NULL) { | |||
fd_set rfds; | |||
FD_ZERO(&rfds); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i)->getFd(), &rfds); | |||
@@ -602,7 +614,7 @@ int main(int argc, char** argv) | |||
} | |||
} | |||
for (std::list<TcpListener*>::iterator i = listeners.begin (); | |||
for (std::list<SocketListener*>::iterator i = listeners.begin (); | |||
i != listeners.end(); | |||
i++) | |||
if (FD_ISSET((*i)->getFd(), &rfds)) { |
@@ -31,7 +31,7 @@ ManagedListener::ManagedListener(SocketManager* mgr) | |||
ManagedListener::~ManagedListener() { | |||
if (!sockets.empty()) { | |||
std::list<network::TcpListener*>::iterator iter; | |||
std::list<network::SocketListener*>::iterator iter; | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->remListener(*iter); | |||
sockets.clear(); | |||
@@ -62,7 +62,7 @@ void ManagedListener::setFilter(const char* filterStr) { | |||
delete filter; | |||
filter = new network::TcpFilter(filterStr); | |||
if (!sockets.empty() && !localOnly) { | |||
std::list<network::TcpListener*>::iterator iter; | |||
std::list<network::SocketListener*>::iterator iter; | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
(*iter)->setFilter(filter); | |||
} | |||
@@ -80,7 +80,7 @@ bool ManagedListener::isListening() { | |||
} | |||
void ManagedListener::refresh() { | |||
std::list<network::TcpListener*>::iterator iter; | |||
std::list<network::SocketListener*>::iterator iter; | |||
if (!sockets.empty()) { | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->remListener(*iter); | |||
@@ -107,7 +107,7 @@ void ManagedListener::refresh() { | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->addListener(*iter, server, addrChangeNotifier); | |||
} catch (...) { | |||
std::list<network::TcpListener*>::iterator iter2; | |||
std::list<network::SocketListener*>::iterator iter2; | |||
for (iter2 = sockets.begin(); iter2 != iter; ++iter2) | |||
manager->remListener(*iter2); | |||
for (; iter2 != sockets.end(); ++iter2) |
@@ -45,7 +45,7 @@ namespace winvnc { | |||
protected: | |||
void refresh(); | |||
std::list<network::TcpListener*> sockets; | |||
std::list<network::SocketListener*> sockets; | |||
network::TcpFilter* filter; | |||
rfb::win32::SocketManager* manager; | |||
rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier; |