aboutsummaryrefslogtreecommitdiffstats
path: root/common/network
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
commita2adc8d4cfdf7336ce9192414c5e775224742a97 (patch)
tree0fc9f229bd40a2de342d91338798033da8ebd7bc /common/network
parent4fc2026b9595e9425f50616d18781995aebe495b (diff)
downloadtigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.tar.gz
tigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.zip
Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'common/network')
-rw-r--r--common/network/Makefile.in17
-rw-r--r--common/network/Socket.h149
-rw-r--r--common/network/TcpSocket.cxx499
-rw-r--r--common/network/TcpSocket.h105
-rw-r--r--common/network/network.dsp129
5 files changed, 899 insertions, 0 deletions
diff --git a/common/network/Makefile.in b/common/network/Makefile.in
new file mode 100644
index 00000000..8aed303a
--- /dev/null
+++ b/common/network/Makefile.in
@@ -0,0 +1,17 @@
+
+SRCS = TcpSocket.cxx
+
+OBJS = $(SRCS:.cxx=.o)
+
+DIR_CPPFLAGS = -I$(top_srcdir) @SOCKLEN_T_DEFINE@
+
+library = libnetwork.a
+
+all:: $(library)
+
+$(library): $(OBJS)
+ rm -f $(library)
+ $(AR) $(library) $(OBJS)
+ $(RANLIB) $(library)
+
+# followed by boilerplate.mk
diff --git a/common/network/Socket.h b/common/network/Socket.h
new file mode 100644
index 00000000..b93da2ef
--- /dev/null
+++ b/common/network/Socket.h
@@ -0,0 +1,149 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Socket.h - abstract base-class for any kind of network stream/socket
+
+#ifndef __NETWORK_SOCKET_H__
+#define __NETWORK_SOCKET_H__
+
+#include <limits.h>
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
+#include <rdr/Exception.h>
+
+namespace network {
+
+ 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;
+ }
+ }
+ 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_;}
+
+ // information about this end of the socket
+ virtual char* getMyAddress() = 0; // a string e.g. "192.168.0.1"
+ virtual int getMyPort() = 0;
+ virtual char* getMyEndpoint() = 0; // <address>::<port>
+
+ // 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;}
+
+ 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) {}
+ rdr::FdInStream* instream;
+ rdr::FdOutStream* outstream;
+ bool ownStreams;
+ bool isShutdown_;
+ bool queryConnection;
+ };
+
+ class ConnectionFilter {
+ public:
+ virtual bool verifyConnection(Socket* s) = 0;
+ };
+
+ class SocketListener {
+ public:
+ SocketListener() : fd(0), filter(0) {}
+ virtual ~SocketListener() {}
+
+ // shutdown() stops the socket from accepting further connections
+ virtual void shutdown() = 0;
+
+ // 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;
+
+ // setFilter() applies the specified filter to all new connections
+ void setFilter(ConnectionFilter* f) {filter = f;}
+ int getFd() {return fd;}
+ protected:
+ int fd;
+ ConnectionFilter* filter;
+ };
+
+ struct SocketException : public rdr::SystemException {
+ SocketException(const char* text, int err_) : rdr::SystemException(text, err_) {}
+ };
+
+ class SocketServer {
+ public:
+ virtual ~SocketServer() {}
+
+ // addSocket() tells the server to serve the Socket. The caller
+ // retains ownership of the Socket - the only way for the server
+ // to discard a Socket is by calling shutdown() on it.
+ // outgoing is set to true if the socket was created by connecting out
+ // to another host, or false if the socket was created by accept()ing
+ // an incoming connection.
+ virtual void addSocket(network::Socket* sock, bool outgoing=false) = 0;
+
+ // removeSocket() tells the server to stop serving the Socket. The
+ // caller retains ownership of the Socket - the server must NOT
+ // delete the Socket! This call is used mainly to cause per-Socket
+ // resources to be freed.
+ virtual void removeSocket(network::Socket* sock) = 0;
+
+ // processSocketEvent() tells the server there is a Socket read event.
+ // The implementation can indicate that the Socket is no longer active
+ // by calling shutdown() on it. The caller will then call removeSocket()
+ // soon after processSocketEvent returns, to allow any pre-Socket
+ // resources to be tidied up.
+ virtual void processSocketEvent(network::Socket* sock) = 0;
+
+ // checkTimeouts() allows the server to check socket timeouts, etc. The
+ // return value is the number of milliseconds to wait before
+ // checkTimeouts() should be called again. If this number is zero then
+ // there is no timeout and checkTimeouts() should be called the next time
+ // an event occurs.
+ virtual int checkTimeouts() = 0;
+
+ virtual bool getDisable() {return false;};
+ };
+
+}
+
+#endif // __NETWORK_SOCKET_H__
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
new file mode 100644
index 00000000..3212ace7
--- /dev/null
+++ b/common/network/TcpSocket.cxx
@@ -0,0 +1,499 @@
+/* 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 WIN32
+//#include <io.h>
+#include <winsock2.h>
+#define errorNumber WSAGetLastError()
+#define snprintf _snprintf
+#else
+#define errorNumber errno
+#define closesocket close
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif
+
+#include <network/TcpSocket.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+
+#ifndef VNC_SOCKLEN_T
+#define VNC_SOCKLEN_T int
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long)-1)
+#endif
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ((unsigned long)0x7F000001)
+#endif
+
+using namespace network;
+using namespace rdr;
+
+static rfb::LogWriter vlog("TcpSocket");
+
+/* Tunnelling support. */
+int network::findFreeTcpPort (void)
+{
+ int sock, port;
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ throw SocketException ("unable to create socket", errorNumber);
+
+ for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
+ addr.sin_port = htons ((unsigned short) port);
+ if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == 0) {
+ closesocket (sock);
+ return port;
+ }
+ }
+ throw SocketException ("no free port in range", 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;
+}
+
+
+// -=- TcpSocket
+
+TcpSocket::TcpSocket(int sock, bool close)
+ : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
+{
+}
+
+TcpSocket::TcpSocket(const char *host, int port)
+ : closeFd(true)
+{
+ int sock;
+
+ // - Create a socket
+ initSockets();
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ throw SocketException("unable to create socket", errorNumber);
+
+#ifndef WIN32
+ // - By default, close the socket on exec()
+ fcntl(sock, F_SETFD, FD_CLOEXEC);
+#endif
+
+ // - Connect it to something
+
+ // Try processing the host as an IP address
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr((char *)host);
+ addr.sin_port = htons(port);
+ if ((int)addr.sin_addr.s_addr == -1) {
+ // Host was not an IP address - try resolving as DNS name
+ struct hostent *hostinfo;
+ hostinfo = gethostbyname((char *)host);
+ if (hostinfo && hostinfo->h_addr) {
+ addr.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
+ } else {
+ int e = errorNumber;
+ closesocket(sock);
+ throw SocketException("unable to resolve host by name", e);
+ }
+ }
+
+ // Attempt to connect to the remote host
+ for (;;) {
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
+ int e = errorNumber;
+#ifndef WIN32
+ if (e == EINTR)
+ continue;
+#endif
+ closesocket(sock);
+ throw SocketException("unable to connect to host", e);
+ } else break;
+ }
+
+ // 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());
+}
+
+char* TcpSocket::getMyAddress() {
+ struct sockaddr_in info;
+ struct in_addr addr;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+
+ getsockname(getFd(), (struct sockaddr *)&info, &info_size);
+ memcpy(&addr, &info.sin_addr, sizeof(addr));
+
+ char* name = inet_ntoa(addr);
+ if (name) {
+ return rfb::strDup(name);
+ } else {
+ return rfb::strDup("");
+ }
+}
+
+int TcpSocket::getMyPort() {
+ return getSockPort(getFd());
+}
+
+char* TcpSocket::getMyEndpoint() {
+ rfb::CharArray address; address.buf = getMyAddress();
+ int port = getMyPort();
+
+ int buflen = strlen(address.buf) + 32;
+ char* buffer = new char[buflen];
+ sprintf(buffer, "%s::%d", address.buf, port);
+ return buffer;
+}
+
+char* TcpSocket::getPeerAddress() {
+ struct sockaddr_in info;
+ struct in_addr addr;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+
+ getpeername(getFd(), (struct sockaddr *)&info, &info_size);
+ memcpy(&addr, &info.sin_addr, sizeof(addr));
+
+ char* name = inet_ntoa(addr);
+ if (name) {
+ return rfb::strDup(name);
+ } else {
+ return rfb::strDup("");
+ }
+}
+
+int TcpSocket::getPeerPort() {
+ struct sockaddr_in info;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+
+ getpeername(getFd(), (struct sockaddr *)&info, &info_size);
+ return ntohs(info.sin_port);
+}
+
+char* TcpSocket::getPeerEndpoint() {
+ rfb::CharArray address; address.buf = getPeerAddress();
+ int port = getPeerPort();
+
+ int buflen = strlen(address.buf) + 32;
+ char* buffer = new char[buflen];
+ sprintf(buffer, "%s::%d", address.buf, port);
+ return buffer;
+}
+
+bool TcpSocket::sameMachine() {
+ struct sockaddr_in peeraddr, myaddr;
+ VNC_SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+
+ getpeername(getFd(), (struct sockaddr *)&peeraddr, &addrlen);
+ getsockname(getFd(), (struct sockaddr *)&myaddr, &addrlen);
+
+ return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
+}
+
+void TcpSocket::shutdown()
+{
+ Socket::shutdown();
+ ::shutdown(getFd(), 2);
+}
+
+bool TcpSocket::enableNagles(int sock, bool enable) {
+ int one = enable ? 0 : 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ int e = errorNumber;
+ vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
+ return false;
+ }
+ return true;
+}
+
+bool TcpSocket::isSocket(int sock)
+{
+ struct sockaddr_in info;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+ return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
+}
+
+bool TcpSocket::isConnected(int sock)
+{
+ struct sockaddr_in info;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+ return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
+}
+
+int TcpSocket::getSockPort(int sock)
+{
+ struct sockaddr_in info;
+ VNC_SOCKLEN_T info_size = sizeof(info);
+ if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
+ return 0;
+ return ntohs(info.sin_port);
+}
+
+
+TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_)
+ : closeFd(close_)
+{
+ if (sock != -1) {
+ fd = sock;
+ return;
+ }
+
+ initSockets();
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ throw SocketException("unable to create listening socket", errorNumber);
+
+#ifndef WIN32
+ // - By default, close the socket on exec()
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ int one = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one)) < 0) {
+ int e = errorNumber;
+ closesocket(fd);
+ throw SocketException("unable to create listening socket", e);
+ }
+#endif
+
+ // - Bind it to the desired port
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if (localhostOnly)
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ int e = errorNumber;
+ closesocket(fd);
+ throw SocketException("unable to bind listening socket", e);
+ }
+
+ // - Set it to be a listening socket
+ if (listen(fd, 5) < 0) {
+ int e = errorNumber;
+ closesocket(fd);
+ throw SocketException("unable to set socket to listening mode", e);
+ }
+}
+
+TcpListener::~TcpListener() {
+ if (closeFd) 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;
+}
+
+void TcpListener::getMyAddresses(std::list<char*>* result) {
+ const hostent* addrs = gethostbyname(0);
+ if (addrs == 0)
+ throw rdr::SystemException("gethostbyname", errorNumber);
+ if (addrs->h_addrtype != AF_INET)
+ throw rdr::Exception("getMyAddresses: bad family");
+ for (int i=0; addrs->h_addr_list[i] != 0; i++) {
+ const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
+ char* addr = new char[strlen(addrC)+1];
+ strcpy(addr, addrC);
+ result->push_back(addr);
+ }
+}
+
+int TcpListener::getMyPort() {
+ return TcpSocket::getSockPort(getFd());
+}
+
+
+TcpFilter::TcpFilter(const char* spec) {
+ rfb::CharArray tmp;
+ tmp.buf = rfb::strDup(spec);
+ while (tmp.buf) {
+ rfb::CharArray first;
+ rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
+ if (strlen(first.buf))
+ filter.push_back(parsePattern(first.buf));
+ }
+}
+
+TcpFilter::~TcpFilter() {
+}
+
+
+static bool
+patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
+ unsigned long address = inet_addr((char *)value);
+ if (address == INADDR_NONE) return false;
+ return ((pattern.address & pattern.mask) == (address & pattern.mask));
+}
+
+bool
+TcpFilter::verifyConnection(Socket* s) {
+ rfb::CharArray name;
+
+ name.buf = s->getPeerAddress();
+ std::list<TcpFilter::Pattern>::iterator i;
+ for (i=filter.begin(); i!=filter.end(); i++) {
+ if (patternMatchIP(*i, name.buf)) {
+ switch ((*i).action) {
+ case Accept:
+ vlog.debug("ACCEPT %s", name.buf);
+ return true;
+ case Query:
+ vlog.debug("QUERY %s", name.buf);
+ s->setRequiresQuery();
+ return true;
+ case Reject:
+ vlog.debug("REJECT %s", name.buf);
+ return false;
+ }
+ }
+ }
+
+ vlog.debug("[REJECT] %s", name.buf);
+ return false;
+}
+
+
+TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
+ TcpFilter::Pattern pattern;
+
+ bool expandMask = false;
+ rfb::CharArray addr, mask;
+
+ if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
+ if (rfb::strContains(mask.buf, '.')) {
+ pattern.mask = inet_addr(mask.buf);
+ } else {
+ pattern.mask = atoi(mask.buf);
+ expandMask = true;
+ }
+ } else {
+ pattern.mask = 32;
+ expandMask = true;
+ }
+ if (expandMask) {
+ unsigned long expanded = 0;
+ // *** check endianness!
+ for (int i=0; i<(int)pattern.mask; i++)
+ expanded |= 1<<(31-i);
+ pattern.mask = htonl(expanded);
+ }
+
+ pattern.address = inet_addr(addr.buf) & pattern.mask;
+ if ((pattern.address == INADDR_NONE) ||
+ (pattern.address == 0)) pattern.mask = 0;
+
+ switch(p[0]) {
+ case '+': pattern.action = TcpFilter::Accept; break;
+ case '-': pattern.action = TcpFilter::Reject; break;
+ case '?': pattern.action = TcpFilter::Query; break;
+ };
+
+ return pattern;
+}
+
+char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
+ in_addr tmp;
+ rfb::CharArray addr, mask;
+ tmp.s_addr = p.address;
+ addr.buf = rfb::strDup(inet_ntoa(tmp));
+ tmp.s_addr = p.mask;
+ mask.buf = rfb::strDup(inet_ntoa(tmp));
+ char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
+ switch (p.action) {
+ case Accept: result[0] = '+'; break;
+ case Reject: result[0] = '-'; break;
+ case Query: result[0] = '?'; break;
+ };
+ result[1] = 0;
+ strcat(result, addr.buf);
+ strcat(result, "/");
+ strcat(result, mask.buf);
+ return result;
+}
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
new file mode 100644
index 00000000..774c6e13
--- /dev/null
+++ b/common/network/TcpSocket.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- TcpSocket.h - base-class for TCP stream sockets.
+// This header also defines the TcpListener class, used
+// to listen for incoming socket connections over TCP
+//
+// NB: Any file descriptors created by the TcpSocket or
+// TcpListener classes are close-on-exec if the OS supports
+// it. TcpSockets initialised with a caller-supplied fd
+// are NOT set to close-on-exec.
+
+#ifndef __NETWORK_TCP_SOCKET_H__
+#define __NETWORK_TCP_SOCKET_H__
+
+#include <network/Socket.h>
+
+#include <list>
+
+/* Tunnelling support. */
+#define TUNNEL_PORT_OFFSET 5500
+
+namespace network {
+
+ /* Tunnelling support. */
+ int findFreeTcpPort (void);
+
+ class TcpSocket : public Socket {
+ public:
+ TcpSocket(int sock, bool close=true);
+ TcpSocket(const char *name, int port);
+ virtual ~TcpSocket();
+
+ virtual char* getMyAddress();
+ virtual int getMyPort();
+ virtual char* getMyEndpoint();
+
+ virtual char* getPeerAddress();
+ virtual int getPeerPort();
+ virtual char* getPeerEndpoint();
+ virtual bool sameMachine();
+
+ virtual void shutdown();
+
+ static bool enableNagles(int sock, bool enable);
+ static bool isSocket(int sock);
+ static bool isConnected(int sock);
+ static int getSockPort(int sock);
+ private:
+ bool closeFd;
+ };
+
+ class TcpListener : public SocketListener {
+ public:
+ TcpListener(int port, bool localhostOnly=false, int sock=-1,
+ bool close=true);
+ virtual ~TcpListener();
+
+ virtual void shutdown();
+ virtual Socket* accept();
+
+ void getMyAddresses(std::list<char*>* addrs);
+ int getMyPort();
+
+ private:
+ bool closeFd;
+ };
+
+ class TcpFilter : public ConnectionFilter {
+ public:
+ TcpFilter(const char* filter);
+ virtual ~TcpFilter();
+
+ virtual bool verifyConnection(Socket* s);
+
+ typedef enum {Accept, Reject, Query} Action;
+ struct Pattern {
+ Action action;
+ unsigned long address;
+ unsigned long mask;
+ };
+ static Pattern parsePattern(const char* s);
+ static char* patternToStr(const Pattern& p);
+ protected:
+ std::list<Pattern> filter;
+ };
+
+}
+
+#endif // __NETWORK_TCP_SOCKET_H__
diff --git a/common/network/network.dsp b/common/network/network.dsp
new file mode 100644
index 00000000..5e23a179
--- /dev/null
+++ b/common/network/network.dsp
@@ -0,0 +1,129 @@
+# Microsoft Developer Studio Project File - Name="network" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=network - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "network.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "network.mak" CFG="network - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "network - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "network - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "network - Win32 Debug Unicode" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "network - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "..\Release\network"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O1 /I ".." /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "network - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "..\Debug\network"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "network - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "network___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "network___Win32_Debug_Unicode"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "..\Debug_Unicode\network"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "network - Win32 Release"
+# Name "network - Win32 Debug"
+# Name "network - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\TcpSocket.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\Socket.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TcpSocket.h
+# End Source File
+# End Group
+# End Target
+# End Project