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: ") +