From 32d0d68a5304d7a461e9c34da1dae124a467a98a Mon Sep 17 00:00:00 2001 From: Constantin Kaplinsky Date: Sun, 16 Apr 2006 06:47:16 +0000 Subject: [PATCH] The "network" library merged with VNC 4.1.1 code. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@521 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- network/Socket.h | 73 +++++++++++++++++++++++++++---------------- network/TcpSocket.cxx | 53 ++++++++++++++++++------------- network/TcpSocket.h | 7 ++--- 3 files changed, 80 insertions(+), 53 deletions(-) diff --git a/network/Socket.h b/network/Socket.h index 09d88bec..b93da2ef 100644 --- a/network/Socket.h +++ b/network/Socket.h @@ -1,5 +1,5 @@ -/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved. - * +/* 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 @@ -21,6 +21,7 @@ #ifndef __NETWORK_SOCKET_H__ #define __NETWORK_SOCKET_H__ +#include #include #include #include @@ -32,9 +33,10 @@ namespace network { Socket(int fd) : instream(new rdr::FdInStream(fd)), outstream(new rdr::FdOutStream(fd)), - own_streams(true) {} + ownStreams(true), isShutdown_(false), + queryConnection(false) {} virtual ~Socket() { - if (own_streams) { + if (ownStreams) { delete instream; delete outstream; } @@ -42,7 +44,10 @@ namespace network { rdr::FdInStream &inStream() {return *instream;} rdr::FdOutStream &outStream() {return *outstream;} int getFd() {return outstream->getFd();} - virtual void shutdown() = 0; + + // 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" @@ -57,19 +62,26 @@ namespace network { // 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), own_streams(false) {} + Socket() : instream(0), outstream(0), ownStreams(false), + isShutdown_(false), queryConnection(false) {} Socket(rdr::FdInStream* i, rdr::FdOutStream* o, bool own) - : instream(i), outstream(o), own_streams(own) {} + : instream(i), outstream(o), ownStreams(own), + isShutdown_(false), queryConnection(false) {} rdr::FdInStream* instream; rdr::FdOutStream* outstream; - bool own_streams; + bool ownStreams; + bool isShutdown_; + bool queryConnection; }; class ConnectionFilter { public: virtual bool verifyConnection(Socket* s) = 0; - virtual bool queryUserAcceptConnection(Socket*) {return false;} }; class SocketListener { @@ -85,6 +97,7 @@ namespace network { // 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: @@ -100,28 +113,34 @@ namespace network { public: virtual ~SocketServer() {} - // addClient() tells the server to manage the socket. - // If the server can't manage the socket, it must shutdown() it. - virtual void addClient(network::Socket* sock) = 0; - - // processSocketEvent() tells the server there is a socket read event. - // If there is an error, or the socket has been closed/shutdown then - // the server MUST delete the socket AND return false. - virtual bool processSocketEvent(network::Socket* sock) = 0; + // 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. + // 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; - // soonestTimeout() is a function to help work out the soonest of several - // timeouts. - static void soonestTimeout(int* timeout, int newTimeout) { - if (newTimeout && (!*timeout || newTimeout < *timeout)) - *timeout = newTimeout; - } virtual bool getDisable() {return false;}; }; diff --git a/network/TcpSocket.cxx b/network/TcpSocket.cxx index 035c7f26..3212ace7 100644 --- a/network/TcpSocket.cxx +++ b/network/TcpSocket.cxx @@ -1,5 +1,5 @@ -/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved. - * +/* 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 @@ -81,8 +81,11 @@ int network::findFreeTcpPort (void) } -void -TcpSocket::initTcpSockets() { +// -=- Socket initialisation +static bool socketsInitialised = false; +static void initSockets() { + if (socketsInitialised) + return; #ifdef WIN32 WORD requiredVersion = MAKEWORD(2,0); WSADATA initResult; @@ -92,8 +95,10 @@ TcpSocket::initTcpSockets() { #else signal(SIGPIPE, SIG_IGN); #endif + socketsInitialised = true; } + // -=- TcpSocket TcpSocket::TcpSocket(int sock, bool close) @@ -107,6 +112,7 @@ TcpSocket::TcpSocket(const char *host, int port) int sock; // - Create a socket + initSockets(); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) throw SocketException("unable to create socket", errorNumber); @@ -149,18 +155,13 @@ TcpSocket::TcpSocket(const char *host, int port) } else break; } - int one = 1; - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (char *)&one, sizeof(one)) < 0) { - int e = errorNumber; - closesocket(sock); - throw SocketException("unable to setsockopt TCP_NODELAY", e); - } + // Disable Nagle's algorithm, to reduce latency + enableNagles(sock, false); // Create the input and output streams instream = new FdInStream(sock); outstream = new FdOutStream(sock); - own_streams = true; + ownStreams = true; } TcpSocket::~TcpSocket() { @@ -244,9 +245,21 @@ bool TcpSocket::sameMachine() { 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; @@ -279,12 +292,13 @@ TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_) 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(sock, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFD, FD_CLOEXEC); int one = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, @@ -345,14 +359,8 @@ TcpListener::accept() { fcntl(new_sock, F_SETFD, FD_CLOEXEC); #endif - // Disable Nagle's algorithm - int one = 1; - if (setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, - (char *)&one, sizeof(one)) < 0) { - int e = errorNumber; - closesocket(new_sock); - throw SocketException("unable to setsockopt TCP_NODELAY", e); - } + // 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); @@ -418,7 +426,8 @@ TcpFilter::verifyConnection(Socket* s) { return true; case Query: vlog.debug("QUERY %s", name.buf); - return queryUserAcceptConnection(s); + s->setRequiresQuery(); + return true; case Reject: vlog.debug("REJECT %s", name.buf); return false; diff --git a/network/TcpSocket.h b/network/TcpSocket.h index 74697829..774c6e13 100644 --- a/network/TcpSocket.h +++ b/network/TcpSocket.h @@ -1,5 +1,5 @@ -/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved. - * +/* 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 @@ -57,8 +57,7 @@ namespace network { virtual void shutdown(); - static void initTcpSockets(); - + static bool enableNagles(int sock, bool enable); static bool isSocket(int sock); static bool isConnected(int sock); static int getSockPort(int sock); -- 2.39.5