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,12 +694,19 @@ 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) {
// 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);
}
}
// increase default filter level for daemon. the user must
// explicitly request another level for a daemon.

View File

@ -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,

View File

@ -28,6 +28,10 @@
<td><a href="mailto:vttom@users.sourceforge.net">Tom Chadwick</a></td>
<td>PageUp/PageDown on X servers without mouse wheel support</td>
</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>
</p>
</body>

View File

@ -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

View File

@ -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<int>(suffixPort);
hostname.erase(i);
m_hostname, m_port);
}
// trim port from hostname
m_hostname.erase(i);
// save port
m_port = static_cast<int>(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);
}
}

View File

@ -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

View File

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