Skip to content
Browse files

Always use the loopback interface when local

If the backend is local to the frontend then we will always use the
loopback interface instead of connecting on the external IP. This adds
some resilience to setups where the network connection may drop, e.g.
using wifi - especially Ubuntu which removes the IP from the interface
if it detects that the network is unreachable.
  • Loading branch information...
1 parent fcb124d commit 50606cd50a7f1e951d5bdec4ffbb9c137bbbc5c2 @stuartm stuartm committed Aug 11, 2011
Showing with 42 additions and 2 deletions.
  1. +36 −1 mythtv/libs/libmythbase/mythsocket.cpp
  2. +6 −1 mythtv/libs/libmythbase/mythsocket.h
View
37 mythtv/libs/libmythbase/mythsocket.cpp
@@ -13,6 +13,8 @@
// Qt
#include <QByteArray>
#include <QHostInfo>
+#include <QNetworkInterface> // for QNetworkInterface::allAddresses ()
+#include <QAbstractSocket> // for QAbstractSocket::NetworkLayerProtocol
#include <QMap>
#include <QCoreApplication>
@@ -37,6 +39,8 @@ const uint MythSocket::kLongTimeout = kMythSocketLongTimeout;
QMutex MythSocket::s_readyread_thread_lock;
MythSocketThread *MythSocket::s_readyread_thread = NULL;
+QMap<QString, QHostAddress::SpecialAddress> MythSocket::s_loopback_cache;
+
MythSocket::MythSocket(int socket, MythSocketCBs *cb)
: MSocketDevice(MSocketDevice::Stream), m_cb(cb),
m_useReadyReadCallback(true),
@@ -752,6 +756,7 @@ void MythSocket::Unlock(bool wake_readyread) const
bool MythSocket::connect(const QString &host, quint16 port)
{
QHostAddress hadr;
+
if (!hadr.setAddress(host))
{
QHostInfo info = QHostInfo::fromName(host);
@@ -774,15 +779,45 @@ bool MythSocket::connect(const QString &host, quint16 port)
* \brief connect to host
* \return true on success
*/
-bool MythSocket::connect(const QHostAddress &addr, quint16 port)
+bool MythSocket::connect(const QHostAddress &hadr, quint16 port)
{
+ QHostAddress addr = hadr;
+
if (state() == Connected)
{
LOG(VB_SOCKET, LOG_ERR, LOC +
"connect() called with already open socket, closing");
close();
}
+ bool usingLoopback = false;
+ if (s_loopback_cache.contains(addr.toString()))
+ {
+ addr = QHostAddress(s_loopback_cache.value(addr.toString()));
+ usingLoopback = true;
+ }
+ else
+ {
+ QList<QHostAddress> localIPs = QNetworkInterface::allAddresses();
+ for (int i = 0; i < localIPs.count() && !usingLoopback; ++i)
+ {
+ if (addr == localIPs[i])
+ {
+ QHostAddress::SpecialAddress loopback = QHostAddress::LocalHost;
+ if (addr.protocol() == QAbstractSocket::IPv6Protocol)
+ loopback = QHostAddress::LocalHostIPv6;
+
+ s_loopback_cache[addr.toString()] = loopback;
+ addr = QHostAddress(loopback);
+ usingLoopback = true;
+ }
+ }
+ }
+
+ if (usingLoopback)
+ LOG(VB_SOCKET, LOG_INFO, LOC + QString("IP is local, using "
+ "loopback address instead"));
+
LOG(VB_SOCKET, LOG_INFO, LOC + QString("attempting connect() to (%1:%2)")
.arg(addr.toString()).arg(port));
View
7 mythtv/libs/libmythbase/mythsocket.h
@@ -9,6 +9,9 @@
#include "mythsocket_cb.h"
#include "mythbaseexp.h"
+template<class T >
+class QList;
+class QString;
class QHostAddress;
class MythSocketThread;
@@ -73,7 +76,7 @@ class MBASE_PUBLIC MythSocket : public MSocketDevice
bool readData(char *data, quint64 len);
bool writeData(const char *data, quint64 len);
- bool connect(const QHostAddress &addr, quint16 port);
+ bool connect(const QHostAddress &hadr, quint16 port);
bool connect(const QString &host, quint16 port);
void Lock(void) const;
@@ -107,6 +110,8 @@ class MBASE_PUBLIC MythSocket : public MSocketDevice
static const uint kSocketBufferSize;
static QMutex s_readyread_thread_lock;
static MythSocketThread *s_readyread_thread;
+
+ static QMap<QString, QHostAddress::SpecialAddress> s_loopback_cache;
};
#endif

0 comments on commit 50606cd

Please sign in to comment.
Something went wrong with that request. Please try again.