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.
This commit is contained in:
crs 2004-12-30 13:28:51 +00:00
parent 34c2be00e5
commit 3d961e4767
7 changed files with 133 additions and 66 deletions

View File

@ -694,11 +694,18 @@ parse(int argc, const char* const* argv)
// save server address // save server address
try { try {
*ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort); *ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
ARG->m_serverAddress->resolve();
} }
catch (XSocketAddress& e) { 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)); ARG->m_pname, e.what(), ARG->m_pname));
bye(kExitFailed); bye(kExitFailed);
}
} }
// increase default filter level for daemon. the user must // increase default filter level for daemon. the user must

View File

@ -744,6 +744,7 @@ parse(int argc, const char* const* argv)
try { try {
*ARG->m_synergyAddress = CNetworkAddress(argv[i + 1], *ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
kDefaultPort); kDefaultPort);
ARG->m_synergyAddress->resolve();
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE, LOG((CLOG_PRINT "%s: %s" BYE,

View File

@ -28,6 +28,10 @@
<td><a href="mailto:vttom@users.sourceforge.net">Tom Chadwick</a></td> <td><a href="mailto:vttom@users.sourceforge.net">Tom Chadwick</a></td>
<td>PageUp/PageDown on X servers without mouse wheel support</td> <td>PageUp/PageDown on X servers without mouse wheel support</td>
</tr> </tr>
<tr>
<td><a href="mailto:toopriddy@users.sourceforge.net">Brent Priddy</a></td>
<td>Re-resolving server hostname on each connection</td>
</tr>
</table> </table>
</p> </p>
</body> </body>

View File

@ -74,6 +74,14 @@ CClient::connect()
} }
try { 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(); IDataSocket* socket = m_socketFactory->create();
// filter socket messages, including a packetizing filter // filter socket messages, including a packetizing filter

View File

@ -22,54 +22,56 @@
// CNetworkAddress // CNetworkAddress
// //
// name re-resolution adapted from a patch by Brent Priddy.
CNetworkAddress::CNetworkAddress() : CNetworkAddress::CNetworkAddress() :
m_address(NULL) m_address(NULL),
m_hostname(),
m_port(0)
{ {
// note -- make no calls to CNetwork socket interface here; // note -- make no calls to CNetwork socket interface here;
// we're often called prior to CNetwork::init(). // 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) { checkPort();
throw XSocketAddress(XSocketAddress::kBadPort, "", port);
}
m_address = ARCH->newAnyAddr(IArchNetwork::kINET); m_address = ARCH->newAnyAddr(IArchNetwork::kINET);
ARCH->setAddrPort(m_address, port); ARCH->setAddrPort(m_address, m_port);
} }
CNetworkAddress::CNetworkAddress(const CNetworkAddress& addr) : CNetworkAddress::CNetworkAddress(const CNetworkAddress& addr) :
m_address(ARCH->copyAddr(addr.m_address)), m_address(addr.m_address != NULL ? ARCH->copyAddr(addr.m_address) : NULL),
m_hostname(addr.m_hostname) m_hostname(addr.m_hostname),
m_port(addr.m_port)
{ {
// do nothing // do nothing
} }
CNetworkAddress::CNetworkAddress(const CString& hostname_, int port) : CNetworkAddress::CNetworkAddress(const CString& hostname, int port) :
m_hostname(hostname_) m_address(NULL),
m_hostname(hostname),
m_port(port)
{ {
if (port == 0) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, port);
}
// check for port suffix // check for port suffix
CString hostname(m_hostname); CString::size_type i = m_hostname.rfind(':');
CString::size_type i = hostname.rfind(':'); if (i != CString::npos && i + 1 < m_hostname.size()) {
if (i != CString::npos && i + 1 < hostname.size()) {
// found a colon. see if it looks like an IPv6 address. // found a colon. see if it looks like an IPv6 address.
bool colonNotation = false; bool colonNotation = false;
bool dotNotation = false; bool dotNotation = false;
bool doubleColon = false; bool doubleColon = false;
for (CString::size_type j = 0; j < i; ++j) { for (CString::size_type j = 0; j < i; ++j) {
if (hostname[j] == ':') { if (m_hostname[j] == ':') {
colonNotation = true; colonNotation = true;
dotNotation = false; dotNotation = false;
if (hostname[j + 1] == ':') { if (m_hostname[j + 1] == ':') {
doubleColon = true; doubleColon = true;
} }
} }
else if (hostname[j] == '.' && colonNotation) { else if (m_hostname[j] == '.' && colonNotation) {
dotNotation = true; dotNotation = true;
} }
} }
@ -80,46 +82,25 @@ CNetworkAddress::CNetworkAddress(const CString& hostname_, int port) :
// the user can replace the double colon with zeros to // the user can replace the double colon with zeros to
// disambiguate. // disambiguate.
if ((!doubleColon || dotNotation) || !colonNotation) { if ((!doubleColon || dotNotation) || !colonNotation) {
// parse port from hostname
char* end; char* end;
long suffixPort = strtol(hostname.c_str() + i + 1, &end, 10); const char* chostname = m_hostname.c_str();
if (end == hostname.c_str() + i + 1 || *end != '\0' || long suffixPort = strtol(chostname + i + 1, &end, 10);
suffixPort <= 0 || suffixPort > 65535) { if (end == chostname + i + 1 || *end != '\0') {
// bogus port
throw XSocketAddress(XSocketAddress::kBadPort, throw XSocketAddress(XSocketAddress::kBadPort,
m_hostname, port); m_hostname, m_port);
}
else {
// good port
port = static_cast<int>(suffixPort);
hostname.erase(i);
} }
// trim port from hostname
m_hostname.erase(i);
// save port
m_port = static_cast<int>(suffixPort);
} }
} }
// if hostname is empty then use wildcard address // check port number
if (hostname.empty()) { checkPort();
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);
}
}
} }
CNetworkAddress::~CNetworkAddress() CNetworkAddress::~CNetworkAddress()
@ -139,11 +120,48 @@ CNetworkAddress::operator=(const CNetworkAddress& addr)
if (m_address != NULL) { if (m_address != NULL) {
ARCH->closeAddr(m_address); ARCH->closeAddr(m_address);
} }
m_hostname = addr.m_hostname;
m_address = newAddr; m_address = newAddr;
m_hostname = addr.m_hostname;
m_port = addr.m_port;
return *this; 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 bool
CNetworkAddress::operator==(const CNetworkAddress& addr) const CNetworkAddress::operator==(const CNetworkAddress& addr) const
{ {
@ -171,7 +189,7 @@ CNetworkAddress::getAddress() const
int int
CNetworkAddress::getPort() const CNetworkAddress::getPort() const
{ {
return (m_address == NULL) ? 0 : ARCH->getAddrPort(m_address); return m_port;
} }
CString CString
@ -179,3 +197,12 @@ CNetworkAddress::getHostname() const
{ {
return m_hostname; return m_hostname;
} }
void
CNetworkAddress::checkPort()
{
// check port number
if (m_port <= 0 || m_port > 65535) {
throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port);
}
}

View File

@ -39,10 +39,12 @@ public:
/*! /*!
Construct the network address for the given \c hostname and \c port. 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 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 it's used, otherwise it's used as a host name. If \c hostname ends
then this throws XSocketAddress. If \c hostname ends in ":[0-9]+" then in ":[0-9]+" then that suffix is extracted and used as the port,
that suffix is extracted and used as the port, overridding the port overridding the port parameter. The resulting port must be a valid
parameter. Neither the extracted port or \c port may be zero. 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); CNetworkAddress(const CString& hostname, int port);
@ -52,6 +54,19 @@ public:
CNetworkAddress& operator=(const CNetworkAddress&); 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 //! @name accessors
//@{ //@{
@ -59,13 +74,13 @@ public:
/*! /*!
Returns true if this address is equal to \p address. Returns true if this address is equal to \p address.
*/ */
bool operator==(const CNetworkAddress&) const; bool operator==(const CNetworkAddress& address) const;
//! Check address inequality //! Check address inequality
/*! /*!
Returns true if this address is not equal to \p address. 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 //! Check address validity
/*! /*!
@ -89,15 +104,19 @@ public:
//! Get hostname //! 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; CString getHostname() const;
//@} //@}
private:
void checkPort();
private: private:
CArchNetAddress m_address; CArchNetAddress m_address;
CString m_hostname; CString m_hostname;
int m_port;
}; };
#endif #endif

View File

@ -780,6 +780,7 @@ CConfig::readSectionOptions(std::istream& s)
if (name == "address") { if (name == "address") {
try { try {
m_synergyAddress = CNetworkAddress(value, kDefaultPort); m_synergyAddress = CNetworkAddress(value, kDefaultPort);
m_synergyAddress.resolve();
} }
catch (XSocketAddress& e) { catch (XSocketAddress& e) {
throw XConfigRead(CString("invalid address argument: ") + throw XConfigRead(CString("invalid address argument: ") +