Skip to content
Permalink
Browse files

This patch adds IPv6 support to mythbackend and mythfrontend. I've be…

…en running

this patch since XMas with no problems at all.

To use IPv6 you just have to run mythtv-setup and configure your backend IPv6 addresses.
This assumes  you have IPv6 configured internally on your lan of course.

The changes are overall fairly small.  One of the biggest things needed
was to encapsulate IPv6 addresses in the URL with [] (otherwise parsing
out a port could be ugly:) )

So for example instead of

   myth://group@fd14:6bf7:21fb::24/file.mpg

 It would be
   myth://group@[fd14:6bf7:21fb::24]/file.mpg

   or if specifying the port

   myth://group@[fd14:6bf7:21fb::24]:6543/file.mpg

To remove all of the duplicated code where we build
the URL I've added a GenMythURL() function to gContext and it will generate
the path and do the right thing when it comes to[]'s , ports  and storage
groups in the URL.

So for example gContext->GenMythURL("fd14:6bf7:21fb::24","6543","file.mpg","Videos")
Happily generates myth://Videos@[fd14:6bf7:21fb::24]:6543/file.mpg

Only the PHP bindings have been updated (for use with mythweb) so far and I have no had
a chance to test this under Windows or OSX as I do not have access to either of those.

This patch does however change MythSocket to no longer assume that a socket will be IPv4.
It will attempt to detect which it should use however based on the IP it is trying to connect to

Bug reports are welcome.
  • Loading branch information
GreyFoxx committed May 16, 2011
1 parent c91c375 commit 8bf5157fdb844dc72e65bfc419e343b6764b58ba
Showing with 213 additions and 85 deletions.
  1. +6 −0 mythtv/bindings/php/MythBackend.php
  2. +7 −7 mythtv/libs/libmyth/programinfo.cpp
  3. +11 −4 mythtv/libs/libmythbase/msocketdevice.cpp
  4. +3 −1 mythtv/libs/libmythbase/msocketdevice.h
  5. +20 −1 mythtv/libs/libmythbase/msocketdevice_unix.cpp
  6. +20 −1 mythtv/libs/libmythbase/msocketdevice_win.cpp
  7. +52 −16 mythtv/libs/libmythbase/mythcorecontext.cpp
  8. +6 −0 mythtv/libs/libmythbase/mythcorecontext.h
  9. +4 −3 mythtv/libs/libmythbase/storagegroup.cpp
  10. +1 −3 mythtv/libs/libmythmetadata/metadataimagedownload.cpp
  11. +3 −3 mythtv/libs/libmythmetadata/videoutils.h
  12. +2 −3 mythtv/libs/libmythtv/tv_rec.cpp
  13. +1 −1 mythtv/libs/libmythui/mythudplistener.cpp
  14. +5 −2 mythtv/libs/libmythui/mythuifilebrowser.cpp
  15. +4 −0 mythtv/libs/libmythupnp/broadcast.h
  16. +4 −0 mythtv/libs/libmythupnp/multicast.cpp
  17. +5 −0 mythtv/libs/libmythupnp/ssdp.cpp
  18. +14 −1 mythtv/libs/libmythupnp/upnpdevice.cpp
  19. +1 −1 mythtv/libs/libmythupnp/upnptasknotify.cpp
  20. +1 −1 mythtv/libs/libmythupnp/upnptasksearch.cpp
  21. +8 −2 mythtv/programs/mythbackend/httpconfig.cpp
  22. +14 −15 mythtv/programs/mythbackend/mainserver.cpp
  23. +1 −1 mythtv/programs/mythbackend/mediaserver.cpp
  24. +1 −1 mythtv/programs/mythfrontend/main.cpp
  25. +1 −1 mythtv/programs/mythfrontend/mediarenderer.cpp
  26. +1 −1 mythtv/programs/mythfrontend/networkcontrol.h
  27. +5 −7 mythtv/programs/mythfrontend/playbackboxhelper.cpp
  28. +9 −5 mythtv/programs/mythfrontend/themechooser.cpp
  29. +1 −1 mythtv/programs/mythlcdserver/lcdserver.cpp
  30. +2 −3 mythtv/programs/mythtranscode/main.cpp
@@ -50,6 +50,12 @@ static function find($host = null, $port = null) {
function __construct($host, $port = null) {
$this->host = $host;
$this->ip = _or(setting('BackendServerIP', $this->host), $host);
// If the IP contains a ':' It's likely an IPv6 address so enclose it in '[]'
if (strpos($this->ip,":") > 0) {
$this->ip = "[" + $this->ip + "]";
}
$this->port = _or($port, _or(setting('BackendServerPort', $this->host), 6543));
$this->port_http = _or(setting('BackendStatusPort', $this->host), _or(setting('BackendStatusPort'), 6544));
}
@@ -2032,19 +2032,19 @@ QString ProgramInfo::GetPlaybackURL(
(gCoreContext->GetNumSetting("MasterBackendOverride", 0)) &&
(RemoteCheckFile(this, false)))
{
tmpURL = QString("myth://") +
gCoreContext->GetSetting("MasterServerIP") + ':' +
gCoreContext->GetSetting("MasterServerPort") + '/' + basename;
tmpURL = gCoreContext->GenMythURL(gCoreContext->GetSetting("MasterServerIP"),
gCoreContext->GetSetting("MasterServerPort").toInt(),
basename);

VERBOSE(VB_FILE, LOC +
QString("GetPlaybackURL: Found @ '%1'").arg(tmpURL));
return tmpURL;
}

// Fallback to streaming from the backend the recording was created on
tmpURL = QString("myth://") +
gCoreContext->GetSettingOnHost("BackendServerIP", hostname) + ':' +
gCoreContext->GetSettingOnHost("BackendServerPort", hostname) + '/' +
basename;
tmpURL = gCoreContext->GenMythURL(gCoreContext->GetSettingOnHost("BackendServerIP", hostname),
gCoreContext->GetSettingOnHost("BackendServerPort", hostname).toInt(),
basename);

VERBOSE(VB_FILE, LOC + QString("GetPlaybackURL: Using default of: '%1'")
.arg(tmpURL));
@@ -173,21 +173,23 @@ MSocketDevice::MSocketDevice( int socket, Type type )
The \a type argument must be either MSocketDevice::Stream for a
reliable, connection-oriented TCP socket, or \c
MSocketDevice::Datagram for an unreliable UDP socket.
The socket is created as an IPv4 socket.
The socket protocol type is defaulting to unknown leaving it to
connect() to determine if an IPv6 or IPv4 type is required.
\sa blocking() protocol()
*/
MSocketDevice::MSocketDevice( Type type )
: fd( -1 ), t( type ), p( 0 ), pp( 0 ), e( NoError ),
d(new MSocketDevicePrivate(IPv4))
d(new MSocketDevicePrivate(Unknown))

// d(new MSocketDevicePrivate(IPv4))
{
#if defined(MSOCKETDEVICE_DEBUG)
qDebug( "MSocketDevice: Created MSocketDevice object %p, type %d",
this, type );
#endif
init();
setSocket( createNewSocket(), type );
//setSocket( createNewSocket(), type );
}

/*!
@@ -276,6 +278,11 @@ MSocketDevice::Protocol MSocketDevice::protocol() const
return d->protocol;
}

void MSocketDevice::setProtocol( Protocol protocol )
{
d->protocol = protocol;
}

/*!
Returns the socket number, or -1 if it is an invalid socket.
@@ -66,6 +66,8 @@ class MBASE_PUBLIC MSocketDevice: public QIODevice
Type type() const;
Protocol protocol() const;

void setProtocol( Protocol protocol );

int socket() const;
virtual void setSocket( int socket, Type type );

@@ -133,6 +135,7 @@ class MBASE_PUBLIC MSocketDevice: public QIODevice
Error error() const;

inline bool isSequential() const { return true; }
int createNewSocket();

protected:
void setError( Error err );
@@ -160,7 +163,6 @@ class MBASE_PUBLIC MSocketDevice: public QIODevice
#endif

static void init();
int createNewSocket();
Protocol getProtocol() const;

private: // Disabled copy constructor and operator=
@@ -391,7 +391,26 @@ void MSocketDevice::setOption( Option opt, int v )
bool MSocketDevice::connect( const QHostAddress &addr, quint16 port )
{
if ( !isValid() )
return false;
{
#if !defined(QT_NO_IPV6)
if ( addr.protocol() == QAbstractSocket::IPv6Protocol ) {
setProtocol(IPv6);
VERBOSE(VB_SOCKET, "MSocketDevice::connect: setting Protocol to IPv6");
}
else
#endif
if ( addr.protocol() == QAbstractSocket::IPv4Protocol ) {
setProtocol(IPv4);
VERBOSE(VB_SOCKET, "MSocketDevice::connect: setting Protocol to IPv4");
}

VERBOSE(VB_SOCKET, "MSocketDevice::connect: attempting to create new socket");
setSocket( createNewSocket(), t);

// If still not valid, give up.
if ( !isValid() )
return false;
}

pa = addr;
pp = port;
@@ -405,7 +405,26 @@ void MSocketDevice::setOption( Option opt, int v )
bool MSocketDevice::connect( const QHostAddress &addr, quint16 port )
{
if ( !isValid() )
return false;
{
#if !defined(QT_NO_IPV6)
if ( addr.protocol() == QAbstractSocket::IPv6Protocol ) {
setProtocol(IPv6);
VERBOSE(VB_SOCKET, "MSocketDevice::connect: setting Protocol to IPv6");
}
else
#endif
if ( addr.protocol() == QAbstractSocket::IPv4Protocol ) {
setProtocol(IPv4);
VERBOSE(VB_SOCKET, "MSocketDevice::connect: setting Protocol to IPv4");
}

VERBOSE(VB_SOCKET, "MSocketDevice::connect: attempting to create new socket");
setSocket( createNewSocket(), t);

// If still not valid, give up.
if ( !isValid() )
return false;
}

pa = addr;
pp = port;
@@ -555,19 +555,59 @@ bool MythCoreContext::IsFrontendOnly(void)
return !backendOnLocalhost;
}

QString MythCoreContext::GenMythURL(QString host, QString port, QString path, QString storageGroup)
{
return GenMythURL(host,port.toInt(),path,storageGroup);
}

QString MythCoreContext::GenMythURL(QString host, int port, QString path, QString storageGroup)
{
QString ret;

QString m_storageGroup;
QString m_host;
QString m_port;

QHostAddress addr(host);

if (!storageGroup.isEmpty())
m_storageGroup = storageGroup + "@";

m_host = host;

#if !defined(QT_NO_IPV6)
// Basically if it appears to be an IPv6 IP surround the IP with [] otherwise don't bother
if (( addr.protocol() == QAbstractSocket::IPv6Protocol ) || (host.contains(":")))
m_host = "[" + host + "]";
#endif

if (port > 0)
m_port = QString(":%1").arg(port);
else
m_port = "";

QString seperator = "/";
if (path.startsWith("/"))
seperator = "";

ret = QString("myth://%1%2%3%4%5").arg(m_storageGroup).arg(m_host).arg(m_port).arg(seperator).arg(path);

//VERBOSE(VB_GENERAL, LOC + QString("GenMythURL returning %1").arg(ret));

return ret;
}


QString MythCoreContext::GetMasterHostPrefix(QString storageGroup)
{
QString ret;

if (IsMasterHost())
{
if (storageGroup.isEmpty())
return QString("myth://%1:%2/").arg(GetSetting("MasterServerIP"))
.arg(GetNumSetting("MasterServerPort", 6543));
else
return QString("myth://%1@%2:%3/").arg(storageGroup)
.arg(GetSetting("MasterServerIP"))
.arg(GetNumSetting("MasterServerPort", 6543));
return GenMythURL(GetSetting("MasterServerIP"),
GetNumSetting("MasterServerPort", 6543),
"",
storageGroup);
}

QMutexLocker locker(&d->m_sockLock);
@@ -579,15 +619,11 @@ QString MythCoreContext::GetMasterHostPrefix(QString storageGroup)

if (d->m_serverSock)
{
if (storageGroup.isEmpty())
ret = QString("myth://%1:%2/")
.arg(d->m_serverSock->peerAddress().toString())
.arg(d->m_serverSock->peerPort());
else
ret = QString("myth://%1@%2:%3/")
.arg(storageGroup)
.arg(d->m_serverSock->peerAddress().toString())
.arg(d->m_serverSock->peerPort());

ret = GenMythURL(d->m_serverSock->peerAddress().toString(),
d->m_serverSock->peerPort(),
"",
storageGroup);
}

return ret;
@@ -81,6 +81,12 @@ class MBASE_PUBLIC MythCoreContext : public MythObservable, public MythSocketCBs
uint timeout_ms = kMythSocketLongTimeout,
bool error_dialog_desired = false);

QString GenMythURL(QString host = QString(), QString port = QString(),
QString path = QString(), QString storageGroup = QString());

QString GenMythURL(QString host = QString(), int port = 0,
QString path = QString(), QString storageGroup = QString());

QString GetMasterHostPrefix(QString storageGroup = QString());
QString GetMasterHostName(void);
QString GetHostName(void);
@@ -806,9 +806,10 @@ QStringList StorageGroup::getGroupDirs(QString groupname, QString host)
* value using QString::fromUtf8() to prevent corruption. */
dirname = QString::fromUtf8(query.value(0)
.toByteArray().constData());
groups += QString("myth://%1@%2%3").arg(groupname)
.arg(query.value(1).toString())
.arg(dirname);
groups += gCoreContext->GenMythURL(query.value(1).toString(),
0,
dirname,
groupname);
}
}

@@ -395,9 +395,7 @@ QString getStorageGroupURL(ArtworkType type, QString host)
else
sgroup = "Default";

return QString("myth://%1@%2:%3/")
.arg(sgroup)
.arg(ip).arg(port);
return gCoreContext->GenMythURL(ip,port,"",sgroup);
}

void cleanThumbnailCacheDir()
@@ -67,9 +67,9 @@ inline QString generate_file_url(
uint port = gCoreContext->GetSettingOnHost("BackendServerPort",
host).toUInt();

return QString("myth://%1@%2:%3/%4")
.arg(StorageGroup::GetGroupToUse(host, storage_group))
.arg(ip).arg(port).arg(path);
return gCoreContext->GenMythURL(ip,port,path,
StorageGroup::GetGroupToUse(host, storage_group));

}

#endif // VIDEOUTILS_H_
@@ -2714,9 +2714,8 @@ void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
tvchain = newchain;
tvchain->ReloadAll();

QString hostprefix = QString("myth://%1:%2/")
.arg(gCoreContext->GetSetting("BackendServerIP"))
.arg(gCoreContext->GetSetting("BackendServerPort"));
QString hostprefix = gCoreContext->GenMythURL(gCoreContext->GetSetting("BackendServerIP"),
gCoreContext->GetSetting("BackendServerPort").toInt());

tvchain->SetHostPrefix(hostprefix);
tvchain->SetCardType(genOpt.cardtype);
@@ -16,7 +16,7 @@ MythUDPListener::MythUDPListener()
m_socket = new QUdpSocket(this);
connect(m_socket, SIGNAL(readyRead()),
this, SLOT(ReadPending()));
if (m_socket->bind(udp_port))
if (m_socket->bind(QHostAddress::AnyIPv6,udp_port))
{
VERBOSE(VB_GENERAL, LOC + QString("bound to port %1").arg(udp_port));
}
@@ -176,8 +176,11 @@ void MythUIFileBrowser::Init(const QString &startPath)
if (!qurl.path().isEmpty())
{
// Force browing of remote SG's to start at their root
m_baseDirectory = QString("myth://%1@%2").arg(qurl.userName())
.arg(qurl.host());
m_baseDirectory = gCoreContext->GenMythURL(qurl.host(),
0,
"",
qurl.userName());

}
else
{
@@ -48,6 +48,10 @@ class QBroadcastSocket : public MSocketDevice
m_address.setAddress( sAddress );
m_port = nPort;

QByteArray addr = sAddress.toLatin1();
setProtocol(IPv4);
setSocket(createNewSocket(), MSocketDevice::Datagram);

int one = 1;

if ( setsockopt( socket(), SOL_SOCKET, SO_BROADCAST, &one, sizeof( one )) < 0)
@@ -62,6 +62,10 @@ QMulticastSocket::QMulticastSocket( QString sAddress, quint16 nPort, quint8 ttl
if (ttl == 0)
ttl = 4;

// Force to IPv4 until a proper upnp spec is complete for ipv6 as well.
setProtocol(IPv4);
setSocket(createNewSocket(), MSocketDevice::Datagram);

// ----------------------------------------------------------------------
// Set the numer of subnets to traverse (TTL)
// ----------------------------------------------------------------------
@@ -205,6 +205,11 @@ void SSDP::PerformSearch( const QString &sST )
QByteArray sRequest = rRequest.toUtf8();

MSocketDevice *pSocket = m_Sockets[ SocketIdx_Search ];
if ( !pSocket->isValid() )
{
pSocket->setProtocol(MSocketDevice::IPv4);
pSocket->setSocket(pSocket->createNewSocket(), MSocketDevice::Datagram);
}

QHostAddress address;
address.setAddress( SSDP_GROUP );

0 comments on commit 8bf5157

Please sign in to comment.
You can’t perform that action at this time.