34 changes: 22 additions & 12 deletions mythtv/libs/libmythbase/mythsocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ MythSocket::MythSocket(
LOG(VB_SOCKET, LOG_INFO, LOC + QString("MythSocket(%1, 0x%2) ctor")
.arg(socket).arg((intptr_t)(cb),0,16));

if (socket != -1)
{
m_tcpSocket->setSocketDescriptor(
socket, QAbstractSocket::ConnectedState,
QAbstractSocket::ReadWrite);
if (!gCoreContext->CheckSubnet(m_tcpSocket))
{
m_tcpSocket->abort();
m_connected = false;
m_useSharedThread = false;
return;
}
else
ConnectHandler(); // already called implicitly above?
}

// Use direct connections so m_tcpSocket can be used
// in the handlers safely since they will be running
// in the same thread as all other m_tcpSocket users.
Expand All @@ -120,15 +136,6 @@ MythSocket::MythSocket(
this, SLOT(CallReadyReadHandler()),
Qt::QueuedConnection);

if (socket != -1)
{
m_tcpSocket->setSocketDescriptor(
socket, QAbstractSocket::ConnectedState,
QAbstractSocket::ReadWrite);

ConnectHandler(); // already called implicitly above?
}

if (!use_shared_thread)
{
m_thread = new MThread(QString("MythSocketThread(%1)").arg(socket));
Expand Down Expand Up @@ -160,9 +167,12 @@ MythSocket::~MythSocket()

if (!m_useSharedThread)
{
m_thread->quit();
m_thread->wait();
delete m_thread;
if (m_thread)
{
m_thread->quit();
m_thread->wait();
delete m_thread;
}
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
* mythtv/bindings/php/MythBackend.php
*/

#define MYTH_DATABASE_VERSION "1346"
#define MYTH_DATABASE_VERSION "1347"


MBASE_PUBLIC const char *GetMythSourceVersion();
Expand Down
33 changes: 16 additions & 17 deletions mythtv/libs/libmythbase/serverpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ static QReadWriteLock naLock;

static QPair<QHostAddress, int> kLinkLocal =
QHostAddress::parseSubnet("169.254.0.0/16");
#if !defined(QT_NO_IPV6)
static QPair<QHostAddress, int> kLinkLocal6 =
QHostAddress::parseSubnet("fe80::/10");
#endif

class PrivUdpSocket : public QUdpSocket
{
Expand All @@ -44,14 +42,12 @@ class PrivUdpSocket : public QUdpSocket
};
static bool contains(QNetworkAddressEntry host, QHostAddress addr)
{
#if !defined(QT_NO_IPV6)
if (addr.protocol() == QAbstractSocket::IPv6Protocol &&
addr.isInSubnet(kLinkLocal6) &&
host.ip().scopeId() != addr.scopeId())
{
return false;
}
#endif
return addr.isInSubnet(host.ip(), host.prefixLength());
}
private:
Expand Down Expand Up @@ -93,19 +89,27 @@ void ServerPool::SelectDefaultListen(bool force)
naList_4.clear();
naList_6.clear();

if (gCoreContext->GetNumSetting("ListenOnAllIps",1))
{
QNetworkAddressEntry entry;
entry.setIp(QHostAddress(QHostAddress::AnyIPv4));
naList_4.append(entry);
entry.setIp(QHostAddress(QHostAddress::AnyIPv6));
naList_6.append(entry);
return;
}

// populate stored IPv4 and IPv6 addresses
QHostAddress config_v4(gCoreContext->resolveSettingAddress(
"BackendServerIP",
QString(),
gCoreContext->ResolveIPv4, true));
bool v4IsSet = config_v4.isNull() ? true : false;
#if !defined(QT_NO_IPV6)
QHostAddress config_v6(gCoreContext->resolveSettingAddress(
"BackendServerIP6",
QString(),
gCoreContext->ResolveIPv6, true));
bool v6IsSet = config_v6.isNull() ? true : false;
#endif
bool allowLinkLocal = gCoreContext->GetNumSetting("AllowLinkLocal", true) > 0;

// loop through all available interfaces
Expand All @@ -121,10 +125,8 @@ void ServerPool::SelectDefaultListen(bool force)
for (qnai = IPs.begin(); qnai != IPs.end(); ++qnai)
{
QHostAddress ip = qnai->ip();
#if !defined(QT_NO_IPV6)
if (ip.protocol() == QAbstractSocket::IPv4Protocol)
{
#endif
if (naList_4.contains(*qnai))
// already defined, skip
continue;
Expand Down Expand Up @@ -194,7 +196,6 @@ void ServerPool::SelectDefaultListen(bool force)
LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
.arg(PRETTYIP_(ip)));

#if !defined(QT_NO_IPV6)
}
else
{
Expand Down Expand Up @@ -257,7 +258,6 @@ void ServerPool::SelectDefaultListen(bool force)
LOG(VB_GENERAL, LOG_DEBUG, QString("Skipping address: %1")
.arg(PRETTYIP_(ip)));
}
#endif
}
}

Expand All @@ -269,15 +269,13 @@ void ServerPool::SelectDefaultListen(bool force)
"interfaces.").arg(config_v4.toString()));
}

#if !defined(QT_NO_IPV6)
if (!v6IsSet && (config_v6 != QHostAddress::LocalHostIPv6)
&& !naList_6.isEmpty())
{
LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
"on %1, but address is not used on any local network "
"interfaces.").arg(PRETTYIP_(config_v6)));
}
#endif

// NOTE: there is no warning for the case where both defined addresses
// are localhost, and neither are found. however this would also
Expand Down Expand Up @@ -333,7 +331,8 @@ QList<QHostAddress> ServerPool::DefaultListenIPv6(void)
QList<QHostAddress> ServerPool::DefaultBroadcast(void)
{
QList<QHostAddress> blist;
blist << DefaultBroadcastIPv4();
if (!gCoreContext->GetNumSetting("ListenOnAllIps",1))
blist << DefaultBroadcastIPv4();
return blist;
}

Expand Down Expand Up @@ -473,7 +472,6 @@ bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
{
QNetworkAddressEntry host;

#if !defined(QT_NO_IPV6)
if (it->protocol() == QAbstractSocket::IPv6Protocol)
{
QList<QNetworkAddressEntry>::iterator iae;
Expand All @@ -487,7 +485,6 @@ bool ServerPool::bind(QList<QHostAddress> addrs, quint16 port,
}
}
else
#endif
{
QList<QNetworkAddressEntry>::iterator iae;
for (iae = naList_4.begin(); iae != naList_4.end(); ++iae)
Expand Down Expand Up @@ -610,7 +607,8 @@ void ServerPool::newTcpConnection(qt_socket_fd_t socket)
return;

QTcpSocket *qsock = new QTcpSocket(this);
if (qsock->setSocketDescriptor(socket))
if (qsock->setSocketDescriptor(socket)
&& gCoreContext->CheckSubnet(qsock))
{
emit newConnection(qsock);
}
Expand All @@ -632,7 +630,8 @@ void ServerPool::newUdpDatagram(void)

socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
emit newDatagram(buffer, sender, senderPort);
if (gCoreContext->CheckSubnet(sender))
emit newDatagram(buffer, sender, senderPort);
}
}

Expand Down
6 changes: 5 additions & 1 deletion mythtv/libs/libmythprotoserver/mythsocketmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ bool MythSocketManager::Listen(int port)
void MythSocketManager::newConnection(qt_socket_fd_t sd)
{
QMutexLocker locker(&m_socketListLock);
m_socketList.insert(new MythSocket(sd, this));
MythSocket *ms = new MythSocket(sd, this);
if (ms->IsConnected())
m_socketList.insert(ms);
else
delete ms;
}

void MythSocketManager::RegisterHandler(SocketRequestHandler *handler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,35 +681,9 @@ bool FileServerHandler::HandleQueryFileHash(SocketHandler *socket,
if (m_fsMap[hostname]->SendReceiveStringList(slist))
hash = slist[0];
}
else
{
// looking for file on unknown host
// assume host is an IP address, and look for matching
// entry in database
MSqlQuery query(MSqlQuery::InitCon());
query.prepare("SELECT hostname FROM settings "
"WHERE value='BackendServerIP' "
" OR value='BackendServerIP6' "
"AND data=:HOSTNAME;");
query.bindValue(":HOSTNAME", hostname);

if (query.exec() && query.next())
{
// address matches an entry
hostname = query.value(0).toString();
if (m_fsMap.contains(hostname))
{
// entry matches a connection
slist.clear();
slist << "QUERY_FILE_HASH"
<< filename
<< storageGroup;

if (m_fsMap[hostname]->SendReceiveStringList(slist))
hash = slist[0];
}
}
}
// I deleted the incorrect SQL select that was supposed to get
// host name from ip address. Since it cannot work and has
// been there 6 years I assume it is not important.
}


Expand Down
54 changes: 54 additions & 0 deletions mythtv/libs/libmythtv/dbcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3338,6 +3338,60 @@ NULL
* WatchTVGuide
*/

if (dbver == "1346")
{
QString master;
// Create new MasterServerName setting
if (gCoreContext->IsMasterHost())
master =
"insert into settings (value,data,hostname) "
"values('MasterServerName','"
+ gCoreContext->GetHostName() + "', null);";
else
master =
"insert into settings (value,data,hostname) "
"select 'MasterServerName', b.hostname, null "
"from settings a, settings b "
"where a.value = 'MasterServerIP' "
"and b.value in ('BackendServerIP','BackendServerIP6')"
"and a.data = b.data;";

const char *updates[] = {
// Create new MasterServerName setting
master.toUtf8(),
// Create new BackendServerAddr setting for each backend server
// Assume using IPV4 value.
"insert into settings (value,data,hostname) "
"select 'BackendServerAddr', data,hostname from settings "
"where value = 'BackendServerIP';",
// Update BackendServerAddr setting for cases where IPV6 is used
"update settings a, settings b "
"set b.data = a.data "
"where a.value = 'BackendServerIP6' "
"and b.hostname = a.hostname "
"and b.value = 'BackendServerAddr' "
"and b.data = '127.0.0.1' "
"and a.data != '::1' "
"and a.data is not null "
"and a.data != ''; ",
// Update BackendServerAddr setting for master backend to
// conform to MasterServerIP setting
"update settings a, settings b, settings c "
"set c.data = a.data "
"where a.value = 'MasterServerIP' " // 1 row
"and b.value = 'MasterServerName' " // 1 row
"and c.value = 'BackendServerAddr' " // 1 row per BE
"and c.hostname = b.data;", // restrict to master
// Delete obsolete settings
"delete from settings "
"where value in ('WatchTVGuide');",
NULL
};

if (!performActualUpdate(&updates[0], "1347", dbver))
return false;
}

return true;
}

Expand Down
10 changes: 9 additions & 1 deletion mythtv/libs/libmythupnp/httpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,8 @@ void HttpWorker::run(void)

#ifndef QT_NO_OPENSSL
QSslSocket *pSslSocket = new QSslSocket();
if (pSslSocket->setSocketDescriptor(m_socket))
if (pSslSocket->setSocketDescriptor(m_socket)
&& gCoreContext->CheckSubnet(pSslSocket))
{
pSslSocket->setSslConfiguration(m_sslConfig);
pSslSocket->startServerEncryption();
Expand Down Expand Up @@ -523,6 +524,13 @@ void HttpWorker::run(void)
{
pSocket = new QTcpSocket();
pSocket->setSocketDescriptor(m_socket);
if (!gCoreContext->CheckSubnet(pSocket))
{
delete pSocket;
pSocket = 0;
return;
}

}

pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1));
Expand Down
10 changes: 9 additions & 1 deletion mythtv/libs/libmythupnp/upnp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
//
//////////////////////////////////////////////////////////////////////////////

#include <QNetworkInterface>

#include "upnptaskcache.h"
#include "mythlogging.h"
#include "serverpool.h"
Expand Down Expand Up @@ -85,7 +87,13 @@ Configuration *UPnp::GetConfiguration()

bool UPnp::Initialize( int nServicePort, HttpServer *pHttpServer )
{
QList<QHostAddress> sList = ServerPool::DefaultListenIPv4();
QList<QHostAddress> sList = ServerPool::DefaultListen();
if (sList.contains(QHostAddress(QHostAddress::AnyIPv4)))
{
sList.removeAll(QHostAddress(QHostAddress::AnyIPv4));
sList.removeAll(QHostAddress(QHostAddress::AnyIPv6));
sList.append(QNetworkInterface::allAddresses());
}
return Initialize( sList, nServicePort, pHttpServer );
}

Expand Down
4 changes: 3 additions & 1 deletion mythtv/libs/libmythupnp/upnptasksearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ void UPnpSearchTask::SendMsg( MSocketDevice *pSocket,

// Avoid announcing the localhost address
if (*it == QHostAddress::LocalHost ||
*it == QHostAddress::LocalHostIPv6)
*it == QHostAddress::LocalHostIPv6 ||
*it == QHostAddress::AnyIPv4 ||
*it == QHostAddress::AnyIPv6)
continue;

// Descope the Link Local address. The scope is only valid
Expand Down
10 changes: 9 additions & 1 deletion mythtv/libs/libmythupnp/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ void WebSocketWorker::SetupSocket()

#ifndef QT_NO_OPENSSL
QSslSocket *pSslSocket = new QSslSocket();
if (pSslSocket->setSocketDescriptor(m_socketFD))
if (pSslSocket->setSocketDescriptor(m_socketFD)
&& gCoreContext->CheckSubnet(pSslSocket))
{
pSslSocket->setSslConfiguration(m_sslConfig);
pSslSocket->startServerEncryption();
Expand Down Expand Up @@ -205,6 +206,13 @@ void WebSocketWorker::SetupSocket()
{
m_socket = new QTcpSocket();
m_socket->setSocketDescriptor(m_socketFD);
if (gCoreContext->CheckSubnet(m_socket))
{
delete m_socket;
m_socket = 0;
return;
}

}

m_socket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1));
Expand Down
105 changes: 42 additions & 63 deletions mythtv/programs/mythbackend/mainserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,44 +260,40 @@ MainServer::MainServer(bool master, int port,
mythserver = new MythServer();
mythserver->setProxy(QNetworkProxy::NoProxy);

// test to make sure listen addresses are available
// no reason to run the backend if the mainserver is not active
QHostAddress config_v4(gCoreContext->resolveSettingAddress(
"BackendServerIP",
QString(),
gCoreContext->ResolveIPv4, true));
bool v4IsSet = config_v4.isNull() ? false : true;
#if !defined(QT_NO_IPV6)
QHostAddress config_v6(gCoreContext->resolveSettingAddress(
"BackendServerIP6",
QString(),
gCoreContext->ResolveIPv6, true));
bool v6IsSet = config_v6.isNull() ? false : true;
#endif
QList<QHostAddress> listenAddrs = mythserver->DefaultListen();
if (!gCoreContext->GetNumSetting("ListenOnAllIps",1))
{
// test to make sure listen addresses are available
// no reason to run the backend if the mainserver is not active
QHostAddress config_v4(gCoreContext->resolveSettingAddress(
"BackendServerIP",
QString(),
gCoreContext->ResolveIPv4, true));
bool v4IsSet = config_v4.isNull() ? false : true;
QHostAddress config_v6(gCoreContext->resolveSettingAddress(
"BackendServerIP6",
QString(),
gCoreContext->ResolveIPv6, true));
bool v6IsSet = config_v6.isNull() ? false : true;

if (v6IsSet && !listenAddrs.contains(config_v6))
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Unable to find IPv6 address to bind");

#if !defined(QT_NO_IPV6)
if (v6IsSet && !listenAddrs.contains(config_v6))
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Unable to find IPv6 address to bind");
#endif

if (v4IsSet && !listenAddrs.contains(config_v4))
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Unable to find IPv4 address to bind");
if (v4IsSet && !listenAddrs.contains(config_v4))
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Unable to find IPv4 address to bind");

if ((v4IsSet && !listenAddrs.contains(config_v4))
#if !defined(QT_NO_IPV6)
&& (v6IsSet && !listenAddrs.contains(config_v6))
#endif
)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to find either IPv4 or IPv6 "
"address we can bind to, exiting");
SetExitCode(GENERIC_EXIT_SOCKET_ERROR, false);
return;
if ((v4IsSet && !listenAddrs.contains(config_v4))
&& (v6IsSet && !listenAddrs.contains(config_v6))
)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to find either IPv4 or IPv6 "
"address we can bind to, exiting");
SetExitCode(GENERIC_EXIT_SOCKET_ERROR, false);
return;
}
}

if (!mythserver->listen(port))
{
SetExitCode(GENERIC_EXIT_SOCKET_ERROR, false);
Expand Down Expand Up @@ -440,7 +436,11 @@ void MainServer::autoexpireUpdate(void)
void MainServer::NewConnection(qt_socket_fd_t socketDescriptor)
{
QWriteLocker locker(&sockListLock);
controlSocketList.insert(new MythSocket(socketDescriptor, this));
MythSocket *ms = new MythSocket(socketDescriptor, this);
if (ms->IsConnected())
controlSocketList.insert(ms);
else
ms-> DecrRef();
}

void MainServer::readyRead(MythSocket *sock)
Expand Down Expand Up @@ -3483,26 +3483,9 @@ void MainServer::HandleQueryFileHash(QStringList &slist, PlaybackSock *pbs)
hash = slave->GetFileHash(filename, storageGroup);
slave->DecrRef();
}
else
{
MSqlQuery query(MSqlQuery::InitCon());
query.prepare("SELECT hostname FROM settings "
"WHERE value='BackendServerIP' "
"OR value='BackendServerIP6' "
"AND data=:HOSTNAME;");
query.bindValue(":HOSTNAME", hostname);

if (query.exec() && query.next())
{
hostname = query.value(0).toString();
slave = GetMediaServerByHostname(hostname);
if (slave)
{
hash = slave->GetFileHash(filename, storageGroup);
slave->DecrRef();
}
}
}
// I deleted the incorrect SQL select that was supposed to get
// host name from ip address. Since it cannot work and has
// been there 6 years I assume it is not important.
}

res << hash;
Expand Down Expand Up @@ -3734,12 +3717,10 @@ void MainServer::HandleSGGetFileList(QStringList &sList,
" path = %3 wanthost = %4")
.arg(groupname).arg(host).arg(path).arg(wantHost));

QString addr4 = gCoreContext->GetBackendServerIP4();
QString addr6 = gCoreContext->GetBackendServerIP6();
QString addr = gCoreContext->GetBackendServerIP();

if ((host.toLower() == wantHost.toLower()) ||
(!addr4.isEmpty() && addr4 == wantHostaddr.toString()) ||
(!addr6.isEmpty() && addr6 == wantHostaddr.toString()))
(!addr.isEmpty() && addr == wantHostaddr.toString()))
{
StorageGroup sg(groupname, host);
LOG(VB_FILE, LOG_INFO, LOC + "HandleSGGetFileList: Getting local info");
Expand Down Expand Up @@ -4018,12 +3999,10 @@ void MainServer::HandleSGFileQuery(QStringList &sList,
LOG(VB_FILE, LOG_INFO, LOC + QString("HandleSGFileQuery: %1")
.arg(gCoreContext->GenMythURL(wantHost, 0, filename, groupname)));

QString addr4 = gCoreContext->GetBackendServerIP4();
QString addr6 = gCoreContext->GetBackendServerIP6();
QString addr = gCoreContext->GetBackendServerIP();

if ((host.toLower() == wantHost.toLower()) ||
(!addr4.isEmpty() && addr4 == wantHostaddr.toString()) ||
(!addr6.isEmpty() && addr6 == wantHostaddr.toString()))
(!addr.isEmpty() && addr == wantHostaddr.toString()))
{
LOG(VB_FILE, LOG_INFO, LOC + "HandleSGFileQuery: Getting local info");
StorageGroup sg(groupname, gCoreContext->GetHostName(), allowFallback);
Expand Down
8 changes: 8 additions & 0 deletions mythtv/programs/mythbackend/mediaserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <QScriptEngine>
#include <QNetworkProxy>
#include <QNetworkInterface>

#include "serviceHosts/mythServiceHost.h"
#include "serviceHosts/guideServiceHost.h"
Expand Down Expand Up @@ -188,6 +189,13 @@ void MediaServer::Init(bool bIsMaster, bool bDisableUPnp /* = false */)
}

QList<QHostAddress> IPAddrList = ServerPool::DefaultListen();
if (IPAddrList.contains(QHostAddress(QHostAddress::AnyIPv4)))
{
IPAddrList.removeAll(QHostAddress(QHostAddress::AnyIPv4));
IPAddrList.removeAll(QHostAddress(QHostAddress::AnyIPv6));
IPAddrList.append(QNetworkInterface::allAddresses());
}

if (IPAddrList.isEmpty())
{
LOG(VB_GENERAL, LOG_ERR,
Expand Down
6 changes: 4 additions & 2 deletions mythtv/programs/mythbackend/services/myth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ DTC::ConnectionInfo* Myth::GetConnectionInfo( const QString &sPin )
QString sServerIP = gCoreContext->GetBackendServerIP();
//QString sPeerIP = pRequest->GetPeerAddress();

if ((params.dbHostName == "localhost") &&
!sServerIP.isEmpty()) // &&
if ((params.dbHostName.compare("localhost",Qt::CaseInsensitive)==0
|| params.dbHostName == "127.0.0.1"
|| params.dbHostName == "::1")
&& !sServerIP.isEmpty()) // &&
//(sServerIP != sPeerIP ))
{
params.dbHostName = sServerIP;
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythbackend/upnpcdsmusic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ UPnpCDSMusic::UPnpCDSMusic()
: UPnpCDSExtension( "Music", "Music",
"object.item.audioItem.musicTrack" )
{
QString sServerIp = gCoreContext->GetBackendServerIP4();
QString sServerIp = gCoreContext->GetBackendServerIP();
int sPort = gCoreContext->GetBackendStatusPort();
m_URIBase.setScheme("http");
m_URIBase.setHost(sServerIp);
Expand Down
4 changes: 2 additions & 2 deletions mythtv/programs/mythbackend/upnpcdstv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ UPnpCDSTv::UPnpCDSTv()
: UPnpCDSExtension( "Recordings", "Recordings",
"object.item.videoItem" )
{
QString sServerIp = gCoreContext->GetBackendServerIP4();
QString sServerIp = gCoreContext->GetBackendServerIP();
int sPort = gCoreContext->GetBackendStatusPort();
m_URIBase.setScheme("http");
m_URIBase.setHost(sServerIp);
Expand Down Expand Up @@ -1049,7 +1049,7 @@ bool UPnpCDSTv::LoadRecordings(const UPnpCDSRequest* pRequest,
// ----------------------------------------------------------------------

if (!m_mapBackendIp.contains( sHostName ))
m_mapBackendIp[ sHostName ] = gCoreContext->GetBackendServerIP4(sHostName);
m_mapBackendIp[ sHostName ] = gCoreContext->GetBackendServerIP(sHostName);

if (!m_mapBackendPort.contains( sHostName ))
m_mapBackendPort[ sHostName ] = gCoreContext->GetBackendStatusPort(sHostName);
Expand Down
6 changes: 3 additions & 3 deletions mythtv/programs/mythbackend/upnpcdsvideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ UPnpCDSVideo::UPnpCDSVideo()
: UPnpCDSExtension( "Videos", "Videos",
"object.item.videoItem" )
{
QString sServerIp = gCoreContext->GetBackendServerIP4();
QString sServerIp = gCoreContext->GetBackendServerIP();
int sPort = gCoreContext->GetBackendStatusPort();
m_URIBase.setScheme("http");
m_URIBase.setHost(sServerIp);
Expand Down Expand Up @@ -687,12 +687,12 @@ bool UPnpCDSVideo::LoadVideos(const UPnpCDSRequest* pRequest,
if (sHostName.isEmpty())
{
m_mapBackendIp[sHostName] =
gCoreContext->GetBackendServerIP4();
gCoreContext->GetBackendServerIP();
}
else
{
m_mapBackendIp[sHostName] =
gCoreContext->GetBackendServerIP4(sHostName);
gCoreContext->GetBackendServerIP(sHostName);
}
}

Expand Down
311 changes: 267 additions & 44 deletions mythtv/programs/mythtv-setup/backendsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,61 @@
#include <QNetworkInterface>


static TransCheckBoxSetting *IsMasterBackend()
{
TransCheckBoxSetting *gc = new TransCheckBoxSetting();
gc->setLabel(QObject::tr("This server is the Master Backend"));
gc->setValue(false);
gc->setHelpText(QObject::tr(
"Enable this if this is the only backend or is the "
"master backend server. If enabled, all frontend and "
"non-master backend machines "
"will connect to this server. To change to a new master "
"backend, run setup on that server and select it as "
"master backend."));
return gc;
};

static GlobalLineEdit *MasterServerName()
{
GlobalLineEdit *gc = new GlobalLineEdit("MasterServerName");
gc->setLabel(QObject::tr("Master Backend Name"));
gc->setValue("");
gc->setRO();
gc->setHelpText(QObject::tr(
"Host name of Master Backend. This is set by selecting "
"\"This server is the Master Backend\" on that server."));
return gc;
};

static HostCheckBox *ListenOnAllIps()
{
HostCheckBox *gc = new HostCheckBox("ListenOnAllIps");
gc->setLabel(QObject::tr("Listen on All IP Addresses"));
gc->setValue(true);
gc->setHelpText(QObject::tr(
"Allow this backend to receive connections on any IP "
"Address assigned to it. Recommended for most users "
"for ease and reliability."));
return gc;
};

static HostCheckBox *AllowConnFromAll()
{
HostCheckBox *gc = new HostCheckBox("AllowConnFromAll");
gc->setLabel(QObject::tr("Allow Connections from all Subnets"));
gc->setValue(false);
gc->setHelpText(QObject::tr(
"Allow this backend to receive connections from any IP "
"address on the internet. NOT recommended for most users. "
"Use this only if you have secure IPV4 and IPV6 " "firewalls."));
return gc;
};

static HostComboBox *LocalServerIP()
{
HostComboBox *gc = new HostComboBox("BackendServerIP");
gc->setLabel(QObject::tr("IPv4 address"));
gc->setLabel(QObject::tr("Listen on IPv4 address"));
QList<QHostAddress> list = QNetworkInterface::allAddresses();
QList<QHostAddress>::iterator it;
for (it = list.begin(); it != list.end(); ++it)
Expand All @@ -35,7 +86,7 @@ static HostComboBox *LocalServerIP()
static HostComboBox *LocalServerIP6()
{
HostComboBox *gc = new HostComboBox("BackendServerIP6");
gc->setLabel(QObject::tr("IPv6 address"));
gc->setLabel(QObject::tr("Listen on IPv6 address"));
QList<QHostAddress> list = QNetworkInterface::allAddresses();
QList<QHostAddress>::iterator it;
for (it = list.begin(); it != list.end(); ++it)
Expand All @@ -49,23 +100,16 @@ static HostComboBox *LocalServerIP6()
}
}

#if defined(QT_NO_IPV6)
gc->setEnabled(false);
gc->setValue("");
#else
if (list.isEmpty())
{
gc->setEnabled(false);
gc->setValue("");
}
else
{
// Allow ability to have no value set, this disable IPv6
gc->addSelection("");
if (list.contains(QHostAddress("::1")))
gc->setValue("::1");
}
#endif

gc->setHelpText(QObject::tr("Enter the IPv6 address of this machine. "
"Use an externally accessible address (ie, not "
Expand All @@ -87,6 +131,37 @@ static HostCheckBox *UseLinkLocal()
return hc;
};

class IpAddressSettings : public TriggeredConfigurationGroup
{
public:
HostCheckBox *listenOnAllIps;
HostComboBox *localServerIP;
HostComboBox *localServerIP6;
explicit IpAddressSettings(/*Setting* trigger*/) :
TriggeredConfigurationGroup(false,false,true,true,false,false,true,true)
{
setLabel(QObject::tr("Listen IP Addresses"));

listenOnAllIps = ListenOnAllIps();
addChild(listenOnAllIps);
setTrigger(listenOnAllIps);

ConfigurationGroup* settings = new VerticalConfigurationGroup(false);
localServerIP = LocalServerIP();
settings->addChild(localServerIP);
localServerIP6 = LocalServerIP6();
settings->addChild(localServerIP6);
settings->addChild(UseLinkLocal());
// show nothing if ListenOnAllIps is on
addTarget("1", new VerticalConfigurationGroup(true));
// show ip addresses if ListenOnAllIps is off
addTarget("0", settings);

};
};



static HostLineEdit *LocalServerPort()
{
HostLineEdit *gc = new HostLineEdit("BackendServerPort");
Expand All @@ -108,26 +183,37 @@ static HostLineEdit *LocalStatusPort()
return gc;
};

static HostComboBox *BackendServerAddr()
{
HostComboBox *gc = new HostComboBox("BackendServerAddr", true);
gc->setLabel(QObject::tr("Primary IP address / DNS name"));
gc->setValue("127.0.0.1");
gc->setHelpText(QObject::tr("The Primary IP address of this backend "
"server. You can select an IP "
"address from the list or type a DNS name "
"or host name. Other systems will contact this "
"server using this address. "
"If you use a host name make sure it is assigned "
"an ip address other than 127.0.0.1 in the hosts "
"file."));
return gc;
};

// Deprecated
static GlobalLineEdit *MasterServerIP()
{
GlobalLineEdit *gc = new GlobalLineEdit("MasterServerIP");
gc->setLabel(QObject::tr("IP address"));
gc->setValue("127.0.0.1");
gc->setHelpText(QObject::tr("The IP address of the master backend "
"server. All frontend and non-master backend machines "
"will connect to this server. If you only have one "
"backend, this should be the same IP address as "
"above."));
return gc;
};

// Deprecated
static GlobalLineEdit *MasterServerPort()
{
GlobalLineEdit *gc = new GlobalLineEdit("MasterServerPort");
gc->setLabel(QObject::tr("Port"));
gc->setValue("6543");
gc->setHelpText(QObject::tr("Unless you've got good reason, "
"don't change this."));
return gc;
};

Expand Down Expand Up @@ -804,44 +890,56 @@ class MythFillSettings : public TriggeredConfigurationGroup
};
};

BackendSettings::BackendSettings() {
BackendSettings::BackendSettings() :
isMasterBackend(0),
localServerPort(0),
backendServerAddr(0),
masterServerName(0),
ipAddressSettings(0),
isLoaded(false),
masterServerIP(0),
masterServerPort(0)
{
// These two are included for backward compatibility -
// used by python bindings. They could be removed later
masterServerIP = MasterServerIP();
masterServerPort = MasterServerPort();

//++ Host Address Backend Setup ++
VerticalConfigurationGroup* server = new VerticalConfigurationGroup(false);
server->setLabel(QObject::tr("Host Address Backend Setup"));
VerticalConfigurationGroup* localServer = new VerticalConfigurationGroup();
localServer->setLabel(QObject::tr("Local Backend") + " (" +
gCoreContext->GetHostName() + ")");
HorizontalConfigurationGroup* localIP =
new HorizontalConfigurationGroup(false, false, true, true);
localIP->addChild(LocalServerIP());
localServer->addChild(localIP);
HorizontalConfigurationGroup* localIP6 =
new HorizontalConfigurationGroup(false, false, true, true);
localIP6->addChild(LocalServerIP6());
localServer->addChild(localIP6);
HorizontalConfigurationGroup *localUseLL =
new HorizontalConfigurationGroup(false, false, true, true);
localUseLL->addChild(UseLinkLocal());
localServer->addChild(localUseLL);
HorizontalConfigurationGroup* localPorts =
new HorizontalConfigurationGroup(false, false, true, true);
localPorts->addChild(LocalServerPort());
localServerPort = LocalServerPort();
localPorts->addChild(localServerPort);
localPorts->addChild(LocalStatusPort());
localServer->addChild(localPorts);
server->addChild(localPorts);
HorizontalConfigurationGroup* localPin =
new HorizontalConfigurationGroup(false, false, true, true);
localPin->addChild(LocalSecurityPin());
localServer->addChild(localPin);
VerticalConfigurationGroup* masterServer = new VerticalConfigurationGroup();
masterServer->setLabel(QObject::tr("Master Backend"));
HorizontalConfigurationGroup* master =
new HorizontalConfigurationGroup(false, false, true, true);
master->addChild(MasterServerIP());
master->addChild(MasterServerPort());
masterServer->addChild(master);
server->addChild(localServer);
server->addChild(masterServer);
server->addChild(localPin);
server->addChild(AllowConnFromAll());
//+++ IP Addresses +++
ipAddressSettings = new IpAddressSettings();
server->addChild(ipAddressSettings);
connect(ipAddressSettings->listenOnAllIps, &HostCheckBox::valueChanged,
this, &BackendSettings::listenChanged);
connect(ipAddressSettings->localServerIP, &HostComboBox::valueChanged,
this, &BackendSettings::listenChanged);
connect(ipAddressSettings->localServerIP6, &HostComboBox::valueChanged,
this, &BackendSettings::listenChanged);
backendServerAddr = BackendServerAddr();
server->addChild(backendServerAddr);
//++ Master Backend ++
isMasterBackend = IsMasterBackend();
connect(isMasterBackend, &TransCheckBoxSetting::valueChanged,
this, &BackendSettings::masterBackendChanged);
server->addChild(isMasterBackend);
masterServerName = MasterServerName();
server->addChild(masterServerName);
addChild(server);

//++ Locale Settings ++
VerticalConfigurationGroup* locale = new VerticalConfigurationGroup(false);
locale->setLabel(QObject::tr("Locale Settings"));
locale->addChild(TVFormat());
Expand Down Expand Up @@ -968,3 +1066,128 @@ BackendSettings::BackendSettings() {
addChild(mythfill);

}

void BackendSettings::masterBackendChanged()
{
if (!isLoaded)
return;
bool ismasterchecked = isMasterBackend->boolValue();
if (ismasterchecked)
masterServerName->setValue(gCoreContext->GetHostName());
else
masterServerName->setValue(priorMasterName);
}

void BackendSettings::listenChanged()
{
if (!isLoaded)
return;
QString currentsetting = backendServerAddr->getValue();
backendServerAddr->clearSelections();
if (ipAddressSettings->listenOnAllIps->boolValue())
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
QList<QHostAddress>::iterator it;
for (it = list.begin(); it != list.end(); ++it)
{
it->setScopeId(QString());
backendServerAddr->addSelection((*it).toString(), (*it).toString());
}
}
else
{
backendServerAddr->addSelection(
ipAddressSettings->localServerIP->getValue());
backendServerAddr->addSelection(
ipAddressSettings->localServerIP6->getValue());
}
// Remove the blank entry that is caused by clearSelections
backendServerAddr->removeSelection(QString());

QHostAddress addr;
if (addr.setAddress(currentsetting))
{
// if prior setting is an ip address
// it only if it is now in the list
if (backendServerAddr->findSelection(currentsetting)
> -1)
backendServerAddr->setValue(currentsetting);
else
backendServerAddr->setValue(0);
}
else if (! currentsetting.isEmpty())
{
// if prior setting was not an ip address, it must
// have been a dns name so add it back and select it.
backendServerAddr->addSelection(currentsetting);
backendServerAddr->setValue(currentsetting);
}
else
backendServerAddr->setValue(0);
}


void BackendSettings::Load(void)
{
isLoaded=false;
ConfigurationWizard::Load();

// These two are included for backward compatibility - only used by python
// bindings. They should be removed later
masterServerIP->Load();
masterServerPort->Load();

QString mastername = masterServerName->getValue();
// new installation - default to master
if (mastername.isEmpty())
mastername = gCoreContext->GetHostName();
bool ismaster = (mastername == gCoreContext->GetHostName());
isMasterBackend->setValue(ismaster);
priorMasterName = mastername;
isLoaded=true;
masterBackendChanged();
listenChanged();
}

void BackendSettings::Save(void)
{
// Setup deprecated backward compatibility settings
if (isMasterBackend->boolValue())
{
QString addr = backendServerAddr->getValue();
QString ip = gCoreContext->resolveAddress(addr);
masterServerIP->setValue(ip);
masterServerPort->setValue(localServerPort->getValue());
}

// These two are included for backward compatibility - only used by python
// bindings. They should be removed later
QString bea = backendServerAddr->getValue();
// initialize them to localhost values
ipAddressSettings->localServerIP->setValue(0);
ipAddressSettings->localServerIP6->setValue(0);
QString ip4 = gCoreContext->resolveAddress
(bea,MythCoreContext::ResolveIPv4);
QString ip6 = gCoreContext->resolveAddress
(bea,MythCoreContext::ResolveIPv6);
// the setValue calls below only set the value if it is in the list.
ipAddressSettings->localServerIP->setValue(ip4);
ipAddressSettings->localServerIP6->setValue(ip6);

ConfigurationWizard::Save();

// These two are included for backward compatibility - only used by python
// bindings. They should be removed later
masterServerIP->Save();
masterServerPort->Save();
}

BackendSettings::~BackendSettings()
{
if (masterServerIP)
delete masterServerIP;
masterServerIP=0;
if (masterServerPort)
delete masterServerPort;
masterServerPort=0;
}
25 changes: 24 additions & 1 deletion mythtv/programs/mythtv-setup/backendsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,33 @@

#include "settings.h"

class BackendSettings : public ConfigurationWizard
class IpAddressSettings;
class BackendSettings : public QObject, public ConfigurationWizard
{
Q_OBJECT
public:
BackendSettings();
virtual void Load(void);
using ConfigurationDialog::Save;
virtual void Save(void);
~BackendSettings();

private:
TransCheckBoxSetting *isMasterBackend;
HostLineEdit *localServerPort;
HostComboBox *backendServerAddr;
GlobalLineEdit *masterServerName;
IpAddressSettings *ipAddressSettings;
bool isLoaded;
QString priorMasterName;

// Deprecated - still here to support bindings
GlobalLineEdit *masterServerIP;
GlobalLineEdit *masterServerPort;

private slots:
void masterBackendChanged(void);
void listenChanged(void);
};

#endif
Expand Down