aboutsummaryrefslogtreecommitdiffstats
path: root/common/network
diff options
context:
space:
mode:
Diffstat (limited to 'common/network')
-rw-r--r--common/network/CMakeLists.txt9
-rw-r--r--common/network/Socket.cxx183
-rw-r--r--common/network/Socket.h66
-rw-r--r--common/network/TcpSocket.cxx209
-rw-r--r--common/network/TcpSocket.h31
-rw-r--r--common/network/UnixSocket.cxx171
-rw-r--r--common/network/UnixSocket.h60
7 files changed, 506 insertions, 223 deletions
diff --git a/common/network/CMakeLists.txt b/common/network/CMakeLists.txt
index b624c8e6..d00ca452 100644
--- a/common/network/CMakeLists.txt
+++ b/common/network/CMakeLists.txt
@@ -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()
diff --git a/common/network/Socket.cxx b/common/network/Socket.cxx
new file mode 100644
index 00000000..9dd8bfe1
--- /dev/null
+++ b/common/network/Socket.cxx
@@ -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;
+}
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 7a30cacf..bfda8a57 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -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;
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index 9603c385..51d77c76 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -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();
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
index c1b142ff..eb6c0958 100644
--- a/common/network/TcpSocket.h
+++ b/common/network/TcpSocket.h
@@ -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 {
diff --git a/common/network/UnixSocket.cxx b/common/network/UnixSocket.cxx
new file mode 100644
index 00000000..bfabc141
--- /dev/null
+++ b/common/network/UnixSocket.cxx
@@ -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;
+}
diff --git a/common/network/UnixSocket.h b/common/network/UnixSocket.h
new file mode 100644
index 00000000..1ffca456
--- /dev/null
+++ b/common/network/UnixSocket.h
@@ -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__