Linux support for Zeroconf using Avahi over DBus.

This commit is contained in:
John Maguire 2011-01-11 20:36:16 +00:00
parent 135b32642e
commit 48bf42b2a5
7 changed files with 431 additions and 1 deletions

View File

@ -630,6 +630,36 @@ if(HAVE_DBUS)
# Gnome Screensaver DBus interface
list(APPEND SOURCES ui/dbusscreensaver.cpp)
if(HAVE_REMOTE)
# TODO: Use CMake macro when it supports -i
find_program(QDBUSXML2CPP qdbusxml2cpp)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.cpp
${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.h
COMMAND ${QDBUSXML2CPP}
dbus/org.freedesktop.Avahi.EntryGroup.xml
-p ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup
-i dbus/metatypes.h
DEPENDS dbus/org.freedesktop.Avahi.EntryGroup.xml
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.h)
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.cpp)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.cpp
${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.h
COMMAND ${QDBUSXML2CPP}
dbus/org.freedesktop.Avahi.Server.xml
-p ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver
-i dbus/metatypes.h
DEPENDS dbus/org.freedesktop.Avahi.Server.xml
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.h)
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.cpp)
endif(HAVE_REMOTE)
endif(HAVE_DBUS)
# Libgpod device backend
@ -727,6 +757,10 @@ if(HAVE_REMOTE)
if(APPLE)
list(APPEND SOURCES remote/bonjour.mm)
endif(APPLE)
if(HAVE_DBUS)
list(APPEND SOURCES remote/avahi.cpp)
endif(HAVE_DBUS)
endif(HAVE_REMOTE)
# OS-specific sources that should be searched for translatable strings even

View File

@ -0,0 +1,99 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.Avahi.EntryGroup">
<method name="Free"/>
<method name="Commit"/>
<method name="Reset"/>
<method name="GetState">
<arg name="state" type="i" direction="out"/>
</method>
<signal name="StateChanged">
<arg name="state" type="i"/>
<arg name="error" type="s"/>
</signal>
<method name="IsEmpty">
<arg name="empty" type="b" direction="out"/>
</method>
<method name="AddService">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="host" type="s" direction="in"/>
<arg name="port" type="q" direction="in"/>
<arg name="txt" type="aay" direction="in"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.In8"
value="QList&lt;QByteArray&gt;" />
</method>
<method name="AddServiceSubtype">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="subtype" type="s" direction="in"/>
</method>
<method name="UpdateServiceTxt">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="txt" type="aay" direction="in"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.In6"
value="QList&lt;QByteArray&gt;" />
</method>
<method name="AddAddress">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="address" type="s" direction="in"/>
</method>
<method name="AddRecord">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="clazz" type="q" direction="in"/>
<arg name="type" type="q" direction="in"/>
<arg name="ttl" type="u" direction="in"/>
<arg name="rdata" type="ay" direction="in"/>
</method>
</interface>
</node>

View File

@ -0,0 +1,218 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.Avahi.Server">
<method name="GetVersionString">
<arg name="version" type="s" direction="out"/>
</method>
<method name="GetAPIVersion">
<arg name="version" type="u" direction="out"/>
</method>
<method name="GetHostName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="SetHostName">
<arg name="name" type="s" direction="in"/>
</method>
<method name="GetHostNameFqdn">
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetDomainName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="IsNSSSupportAvailable">
<arg name="yes" type="b" direction="out"/>
</method>
<method name="GetState">
<arg name="state" type="i" direction="out"/>
</method>
<signal name="StateChanged">
<arg name="state" type="i"/>
<arg name="error" type="s"/>
</signal>
<method name="GetLocalServiceCookie">
<arg name="cookie" type="u" direction="out"/>
</method>
<method name="GetAlternativeHostName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetAlternativeServiceName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceNameByIndex">
<arg name="index" type="i" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceIndexByName">
<arg name="name" type="s" direction="in"/>
<arg name="index" type="i" direction="out"/>
</method>
<method name="ResolveHostName">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="ResolveAddress">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<!--
Disabled as it breaks the code generation due to its _11_ parameters.
<method name="ResolveService">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="type" type="s" direction="out"/>
<arg name="domain" type="s" direction="out"/>
<arg name="host" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="port" type="q" direction="out"/>
<arg name="txt" type="aay" direction="out"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.Out9"
value="QList&lt;QByteArray&gt;" />
<arg name="flags" type="u" direction="out"/>
</method>
-->
<method name="EntryGroupNew">
<arg name="path" type="o" direction="out"/>
</method>
<method name="DomainBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="btype" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceTypeBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="HostNameResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="AddressResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="RecordBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="clazz" type="q" direction="in"/>
<arg name="type" type="q" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
</interface>
</node>

View File

@ -80,6 +80,7 @@ using boost::scoped_ptr;
#include "core/mpris_common.h"
#include "core/mpris.h"
#include "core/mpris2.h"
#include "dbus/metatypes.h"
#include <QDBusArgument>
#include <QDBusConnection>
#include <QImage>
@ -310,8 +311,9 @@ int main(int argc, char *argv[]) {
qDBusRegisterMetaType<QImage>();
qDBusRegisterMetaType<TrackMetadata>();
qDBusRegisterMetaType<TrackIds>();
qDBusRegisterMetaType<QList<QByteArray> >();
// Create the session bus here so it's sure to live in the main thread
// Create the session bus here so it's sure to live in the main thread.
QDBusConnection::sessionBus();
mpris::ArtLoader art_loader;
@ -323,6 +325,10 @@ int main(int argc, char *argv[]) {
#endif
#ifdef HAVE_REMOTE
#ifdef HAVE_DBUS
// Create the system bus here so it's sure to live in the main thread.
QDBusConnection::systemBus();
#endif
Zeroconf* zeroconf = Zeroconf::GetZeroconf();
if (zeroconf) {
HttpServer* server = new HttpServer(&player);

48
src/remote/avahi.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "avahi.h"
#include <QDBusConnection>
#include <QHostInfo>
#include <QtConcurrentRun>
#include <QtDebug>
#include "dbus/avahientrygroup.h"
#include "dbus/avahiserver.h"
void Avahi::Publish(
const QString& domain, const QString& type, const QString& name, quint16 port) {
QtConcurrent::run(Avahi::SyncPublish, domain, type, name, port);
}
void Avahi::SyncPublish(const QString& domain, const QString& type, const QString& name, quint16 port) {
OrgFreedesktopAvahiServerInterface server_interface(
"org.freedesktop.Avahi",
"/",
QDBusConnection::systemBus());
QDBusPendingReply<QDBusObjectPath> reply = server_interface.EntryGroupNew();
reply.waitForFinished();
OrgFreedesktopAvahiEntryGroupInterface entry_group_interface(
"org.freedesktop.Avahi",
reply.value().path(),
QDBusConnection::systemBus());
QDBusPendingReply<> add_reply = entry_group_interface.AddService(
-1, // Interface (Unspecified, ie. all interfaces)
-1, // Protocol (Unspecified, ie. IPv4 & IPv6)
0, // Flags
name, // Service name
type, // Service type
domain, // Domain, ie. local
QString::null, // Hostname (Avahi fills it if it's null)
port, // Port
QList<QByteArray>()); // TXT record
add_reply.waitForFinished();
QDBusPendingReply<> commit_reply = entry_group_interface.Commit();
commit_reply.waitForFinished();
if (commit_reply.isValid()) {
qDebug() << "Remote interface published on Avahi";
}
}

15
src/remote/avahi.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef AVAHI_H
#define AVAHI_H
#include "zeroconf.h"
class Avahi : public Zeroconf {
public:
virtual void Publish(
const QString& domain, const QString& type, const QString& name, quint16 port);
private:
static void SyncPublish(const QString& domain, const QString& type, const QString& name, quint16 port);
};
#endif

View File

@ -1,9 +1,15 @@
#include "zeroconf.h"
#include "config.h"
#ifdef Q_OS_DARWIN
#include "bonjour.h"
#endif
#ifdef HAVE_DBUS
#include "avahi.h"
#endif
Zeroconf* Zeroconf::instance_ = NULL;
Zeroconf* Zeroconf::GetZeroconf() {
@ -11,6 +17,10 @@ Zeroconf* Zeroconf::GetZeroconf() {
#ifdef Q_OS_DARWIN
return new Bonjour();
#endif
#ifdef HAVE_DBUS
return new Avahi();
#endif
}
return instance_;