From 3d961e47673360817e67c80f420e583dec7f4823 Mon Sep 17 00:00:00 2001 From: crs Date: Thu, 30 Dec 2004 13:28:51 +0000 Subject: [PATCH] Adapted and applied patch by Brent Priddy for re-resolving the server hostname on each connection. This allows the client to startup without being able to resolve the server's hostname. It also lets it handle changes in the server's address, a typical scenario when the client is a laptop moving between networks. --- cmd/synergyc/synergyc.cpp | 11 ++- cmd/synergys/synergys.cpp | 1 + doc/authors.html | 4 + lib/client/CClient.cpp | 8 ++ lib/net/CNetworkAddress.cpp | 141 +++++++++++++++++++++--------------- lib/net/CNetworkAddress.h | 33 +++++++-- lib/server/CConfig.cpp | 1 + 7 files changed, 133 insertions(+), 66 deletions(-) diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp index c214034c..2b548be8 100644 --- a/cmd/synergyc/synergyc.cpp +++ b/cmd/synergyc/synergyc.cpp @@ -694,11 +694,18 @@ parse(int argc, const char* const* argv) // save server address try { *ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort); + ARG->m_serverAddress->resolve(); } catch (XSocketAddress& e) { - LOG((CLOG_PRINT "%s: %s" BYE, + // allow an address that we can't look up if we're restartable. + // we'll try to resolve the address each time we connect to the + // server. a bad port will never get better. patch by Brent + // Priddy. + if (!ARG->m_restartable || e.getError() == XSocketAddress::kBadPort) { + LOG((CLOG_PRINT "%s: %s" BYE, ARG->m_pname, e.what(), ARG->m_pname)); - bye(kExitFailed); + bye(kExitFailed); + } } // increase default filter level for daemon. the user must diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp index 7f40264f..a8530dec 100644 --- a/cmd/synergys/synergys.cpp +++ b/cmd/synergys/synergys.cpp @@ -744,6 +744,7 @@ parse(int argc, const char* const* argv) try { *ARG->m_synergyAddress = CNetworkAddress(argv[i + 1], kDefaultPort); + ARG->m_synergyAddress->resolve(); } catch (XSocketAddress& e) { LOG((CLOG_PRINT "%s: %s" BYE, diff --git a/doc/authors.html b/doc/authors.html index f96dfcfd..f908c0bf 100644 --- a/doc/authors.html +++ b/doc/authors.html @@ -28,6 +28,10 @@ Tom Chadwick PageUp/PageDown on X servers without mouse wheel support + + Brent Priddy + Re-resolving server hostname on each connection +

diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index 15092cf6..d339156f 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -74,6 +74,14 @@ CClient::connect() } try { + // resolve the server hostname. do this every time we connect + // in case we couldn't resolve the address earlier or the address + // has changed (which can happen frequently if this is a laptop + // being shuttled between various networks). patch by Brent + // Priddy. + m_serverAddress.resolve(); + + // create the socket IDataSocket* socket = m_socketFactory->create(); // filter socket messages, including a packetizing filter diff --git a/lib/net/CNetworkAddress.cpp b/lib/net/CNetworkAddress.cpp index 758f76dc..7daeed55 100644 --- a/lib/net/CNetworkAddress.cpp +++ b/lib/net/CNetworkAddress.cpp @@ -22,54 +22,56 @@ // CNetworkAddress // +// name re-resolution adapted from a patch by Brent Priddy. + CNetworkAddress::CNetworkAddress() : - m_address(NULL) + m_address(NULL), + m_hostname(), + m_port(0) { // note -- make no calls to CNetwork socket interface here; // we're often called prior to CNetwork::init(). } -CNetworkAddress::CNetworkAddress(int port) +CNetworkAddress::CNetworkAddress(int port) : + m_address(NULL), + m_hostname(), + m_port(port) { - if (port == 0) { - throw XSocketAddress(XSocketAddress::kBadPort, "", port); - } - + checkPort(); m_address = ARCH->newAnyAddr(IArchNetwork::kINET); - ARCH->setAddrPort(m_address, port); + ARCH->setAddrPort(m_address, m_port); } CNetworkAddress::CNetworkAddress(const CNetworkAddress& addr) : - m_address(ARCH->copyAddr(addr.m_address)), - m_hostname(addr.m_hostname) + m_address(addr.m_address != NULL ? ARCH->copyAddr(addr.m_address) : NULL), + m_hostname(addr.m_hostname), + m_port(addr.m_port) { // do nothing } -CNetworkAddress::CNetworkAddress(const CString& hostname_, int port) : - m_hostname(hostname_) +CNetworkAddress::CNetworkAddress(const CString& hostname, int port) : + m_address(NULL), + m_hostname(hostname), + m_port(port) { - if (port == 0) { - throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, port); - } - // check for port suffix - CString hostname(m_hostname); - CString::size_type i = hostname.rfind(':'); - if (i != CString::npos && i + 1 < hostname.size()) { + CString::size_type i = m_hostname.rfind(':'); + if (i != CString::npos && i + 1 < m_hostname.size()) { // found a colon. see if it looks like an IPv6 address. bool colonNotation = false; bool dotNotation = false; bool doubleColon = false; for (CString::size_type j = 0; j < i; ++j) { - if (hostname[j] == ':') { + if (m_hostname[j] == ':') { colonNotation = true; dotNotation = false; - if (hostname[j + 1] == ':') { + if (m_hostname[j + 1] == ':') { doubleColon = true; } } - else if (hostname[j] == '.' && colonNotation) { + else if (m_hostname[j] == '.' && colonNotation) { dotNotation = true; } } @@ -80,46 +82,25 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, int port) : // the user can replace the double colon with zeros to // disambiguate. if ((!doubleColon || dotNotation) || !colonNotation) { + // parse port from hostname char* end; - long suffixPort = strtol(hostname.c_str() + i + 1, &end, 10); - if (end == hostname.c_str() + i + 1 || *end != '\0' || - suffixPort <= 0 || suffixPort > 65535) { - // bogus port + const char* chostname = m_hostname.c_str(); + long suffixPort = strtol(chostname + i + 1, &end, 10); + if (end == chostname + i + 1 || *end != '\0') { throw XSocketAddress(XSocketAddress::kBadPort, - m_hostname, port); - } - else { - // good port - port = static_cast(suffixPort); - hostname.erase(i); + m_hostname, m_port); } + + // trim port from hostname + m_hostname.erase(i); + + // save port + m_port = static_cast(suffixPort); } } - // if hostname is empty then use wildcard address - if (hostname.empty()) { - m_address = ARCH->newAnyAddr(IArchNetwork::kINET); - ARCH->setAddrPort(m_address, port); - } - else { - // look up name - try { - m_address = ARCH->nameToAddr(hostname); - ARCH->setAddrPort(m_address, port); - } - catch (XArchNetworkNameUnknown&) { - throw XSocketAddress(XSocketAddress::kNotFound, hostname, port); - } - catch (XArchNetworkNameNoAddress&) { - throw XSocketAddress(XSocketAddress::kNoAddress, hostname, port); - } - catch (XArchNetworkNameUnsupported&) { - throw XSocketAddress(XSocketAddress::kUnsupported, hostname, port); - } - catch (XArchNetworkName&) { - throw XSocketAddress(XSocketAddress::kUnknown, hostname, port); - } - } + // check port number + checkPort(); } CNetworkAddress::~CNetworkAddress() @@ -139,11 +120,48 @@ CNetworkAddress::operator=(const CNetworkAddress& addr) if (m_address != NULL) { ARCH->closeAddr(m_address); } - m_hostname = addr.m_hostname; m_address = newAddr; + m_hostname = addr.m_hostname; + m_port = addr.m_port; return *this; } +void +CNetworkAddress::resolve() +{ + // discard previous address + if (m_address != NULL) { + ARCH->closeAddr(m_address); + m_address = NULL; + } + + try { + // if hostname is empty then use wildcard address otherwise look + // up the name. + if (m_hostname.empty()) { + m_address = ARCH->newAnyAddr(IArchNetwork::kINET); + } + else { + m_address = ARCH->nameToAddr(m_hostname); + } + } + catch (XArchNetworkNameUnknown&) { + throw XSocketAddress(XSocketAddress::kNotFound, m_hostname, m_port); + } + catch (XArchNetworkNameNoAddress&) { + throw XSocketAddress(XSocketAddress::kNoAddress, m_hostname, m_port); + } + catch (XArchNetworkNameUnsupported&) { + throw XSocketAddress(XSocketAddress::kUnsupported, m_hostname, m_port); + } + catch (XArchNetworkName&) { + throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); + } + + // set port in address + ARCH->setAddrPort(m_address, m_port); +} + bool CNetworkAddress::operator==(const CNetworkAddress& addr) const { @@ -171,7 +189,7 @@ CNetworkAddress::getAddress() const int CNetworkAddress::getPort() const { - return (m_address == NULL) ? 0 : ARCH->getAddrPort(m_address); + return m_port; } CString @@ -179,3 +197,12 @@ CNetworkAddress::getHostname() const { return m_hostname; } + +void +CNetworkAddress::checkPort() +{ + // check port number + if (m_port <= 0 || m_port > 65535) { + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } +} diff --git a/lib/net/CNetworkAddress.h b/lib/net/CNetworkAddress.h index f1e66bab..d29b93b1 100644 --- a/lib/net/CNetworkAddress.h +++ b/lib/net/CNetworkAddress.h @@ -39,10 +39,12 @@ public: /*! Construct the network address for the given \c hostname and \c port. If \c hostname can be parsed as a numerical address then that's how - it's used, otherwise the host name is looked up. If the lookup fails - then this throws XSocketAddress. If \c hostname ends in ":[0-9]+" then - that suffix is extracted and used as the port, overridding the port - parameter. Neither the extracted port or \c port may be zero. + it's used, otherwise it's used as a host name. If \c hostname ends + in ":[0-9]+" then that suffix is extracted and used as the port, + overridding the port parameter. The resulting port must be a valid + port number (zero is not a valid port number) otherwise \c XSocketAddress + is thrown with an error of \c XSocketAddress::kBadPort. The hostname + is not resolved by the c'tor; use \c resolve to do that. */ CNetworkAddress(const CString& hostname, int port); @@ -52,6 +54,19 @@ public: CNetworkAddress& operator=(const CNetworkAddress&); + //! @name manipulators + //@{ + + //! Resolve address + /*! + Resolves the hostname to an address. This can be done any number of + times and is done automatically by the c'tor taking a hostname. + Throws XSocketAddress if resolution is unsuccessful, after which + \c isValid returns false until the next call to this method. + */ + void resolve(); + + //@} //! @name accessors //@{ @@ -59,13 +74,13 @@ public: /*! Returns true if this address is equal to \p address. */ - bool operator==(const CNetworkAddress&) const; + bool operator==(const CNetworkAddress& address) const; //! Check address inequality /*! Returns true if this address is not equal to \p address. */ - bool operator!=(const CNetworkAddress&) const; + bool operator!=(const CNetworkAddress& address) const; //! Check address validity /*! @@ -89,15 +104,19 @@ public: //! Get hostname /*! - Returns the hostname passed to the c'tor sans the port suffix. + Returns the hostname passed to the c'tor sans any port suffix. */ CString getHostname() const; //@} +private: + void checkPort(); + private: CArchNetAddress m_address; CString m_hostname; + int m_port; }; #endif diff --git a/lib/server/CConfig.cpp b/lib/server/CConfig.cpp index dddd2586..360379fb 100644 --- a/lib/server/CConfig.cpp +++ b/lib/server/CConfig.cpp @@ -780,6 +780,7 @@ CConfig::readSectionOptions(std::istream& s) if (name == "address") { try { m_synergyAddress = CNetworkAddress(value, kDefaultPort); + m_synergyAddress.resolve(); } catch (XSocketAddress& e) { throw XConfigRead(CString("invalid address argument: ") +