From 0b3fbdba87e9ecbfaefab9f71203a1c35f1a8b00 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 26 Jan 2014 11:19:17 +0100 Subject: neighbor/upnp: UPnP media server discovery --- Makefile.am | 23 +++++ configure.ac | 3 + src/lib/upnp/ContentDirectoryService.hxx | 5 + src/neighbor/Registry.cxx | 4 + src/neighbor/plugins/UpnpNeighborPlugin.cxx | 139 ++++++++++++++++++++++++++++ src/neighbor/plugins/UpnpNeighborPlugin.hxx | 27 ++++++ 6 files changed, 201 insertions(+) create mode 100644 src/neighbor/plugins/UpnpNeighborPlugin.cxx create mode 100644 src/neighbor/plugins/UpnpNeighborPlugin.hxx diff --git a/Makefile.am b/Makefile.am index 0acca6b31..8a648e45b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -436,6 +436,15 @@ NEIGHBOR_LIBS = \ $(SMBCLIENT_LIBS) \ libneighbor.a +if HAVE_LIBUPNP +libneighbor_a_SOURCES += \ + $(UPNP_SOURCES) \ + src/neighbor/plugins/UpnpNeighborPlugin.cxx src/neighbor/plugins/UpnpNeighborPlugin.hxx +NEIGHBOR_LIBS += \ + $(EXPAT_LIBS) \ + $(UPNP_LIBS) +endif + endif # database plugins @@ -1323,10 +1332,14 @@ if ENABLE_NEIGHBOR_PLUGINS test_run_neighbor_explorer_SOURCES = \ src/Log.cxx src/LogBackend.cxx \ + src/IOThread.cxx \ test/run_neighbor_explorer.cxx test_run_neighbor_explorer_LDADD = \ $(GLIB_LIBS) \ $(NEIGHBOR_LIBS) \ + $(INPUT_LIBS) \ + $(ARCHIVE_LIBS) \ + libtag.a \ libconf.a \ libevent.a \ libfs.a \ @@ -1334,6 +1347,16 @@ test_run_neighbor_explorer_LDADD = \ libthread.a \ libutil.a +if HAVE_LIBUPNP +test_run_neighbor_explorer_SOURCES += src/lib/expat/ExpatParser.cxx +endif + +if ENABLE_DESPOTIFY +test_run_neighbor_explorer_SOURCES += \ + src/lib/despotify/DespotifyUtils.cxx \ + src/lib/despotify/DespotifyUtils.hxx +endif + endif if ENABLE_ARCHIVE diff --git a/configure.ac b/configure.ac index 19ead794b..d65839a40 100644 --- a/configure.ac +++ b/configure.ac @@ -897,6 +897,9 @@ if test x$enable_neighbor_plugins = xauto; then if test x$enable_smbclient = xyes; then enable_neighbor_plugins=yes fi + if test x$enable_upnp = xyes; then + enable_neighbor_plugins=yes + fi fi if test x$enable_neighbor_plugins = xyes; then diff --git a/src/lib/upnp/ContentDirectoryService.hxx b/src/lib/upnp/ContentDirectoryService.hxx index 3c4497be1..0b03df2e7 100644 --- a/src/lib/upnp/ContentDirectoryService.hxx +++ b/src/lib/upnp/ContentDirectoryService.hxx @@ -121,6 +121,11 @@ public: std::list &result, Error &error) const; + gcc_pure + std::string GetURI() const { + return "upnp://" + m_deviceId + "/" + m_serviceType; + } + /** Retrieve the "friendly name" for this server, useful for display. */ const char *getFriendlyName() const { return m_friendlyName.c_str(); diff --git a/src/neighbor/Registry.cxx b/src/neighbor/Registry.cxx index fc9d05ecf..f6d1f97b3 100644 --- a/src/neighbor/Registry.cxx +++ b/src/neighbor/Registry.cxx @@ -21,12 +21,16 @@ #include "Registry.hxx" #include "NeighborPlugin.hxx" #include "plugins/SmbclientNeighborPlugin.hxx" +#include "plugins/UpnpNeighborPlugin.hxx" #include const NeighborPlugin *const neighbor_plugins[] = { #ifdef ENABLE_SMBCLIENT &smbclient_neighbor_plugin, +#endif +#ifdef HAVE_LIBUPNP + &upnp_neighbor_plugin, #endif nullptr }; diff --git a/src/neighbor/plugins/UpnpNeighborPlugin.cxx b/src/neighbor/plugins/UpnpNeighborPlugin.cxx new file mode 100644 index 000000000..253e4c13b --- /dev/null +++ b/src/neighbor/plugins/UpnpNeighborPlugin.cxx @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "UpnpNeighborPlugin.hxx" +#include "lib/upnp/Domain.hxx" +#include "lib/upnp/ClientInit.hxx" +#include "lib/upnp/Discovery.hxx" +#include "lib/upnp/ContentDirectoryService.hxx" +#include "neighbor/NeighborPlugin.hxx" +#include "neighbor/Explorer.hxx" +#include "neighbor/Listener.hxx" +#include "neighbor/Info.hxx" +#include "Log.hxx" + +class UpnpNeighborExplorer final + : public NeighborExplorer, UPnPDiscoveryListener { + struct Server { + std::string name, comment; + + bool alive; + + Server(std::string &&_name, std::string &&_comment) + :name(std::move(_name)), comment(std::move(_comment)), + alive(true) {} + Server(const Server &) = delete; + + gcc_pure + bool operator==(const Server &other) const { + return name == other.name; + } + + gcc_pure + NeighborInfo Export() const { + return { "smb://" + name + "/", comment }; + } + }; + + UPnPDeviceDirectory *discovery; + +public: + UpnpNeighborExplorer(NeighborListener &_listener) + :NeighborExplorer(_listener) {} + + /* virtual methods from class NeighborExplorer */ + virtual bool Open(Error &error) override; + virtual void Close() override; + virtual List GetList() const override; + +private: + /* virtual methods from class UPnPDiscoveryListener */ + virtual void FoundUPnP(const ContentDirectoryService &service) override; + virtual void LostUPnP(const ContentDirectoryService &service) override; +}; + +bool +UpnpNeighborExplorer::Open(Error &error) +{ + UpnpClient_Handle handle; + if (!UpnpClientGlobalInit(handle, error)) + return false; + + discovery = new UPnPDeviceDirectory(handle, this); + if (!discovery->Start(error)) { + delete discovery; + UpnpClientGlobalFinish(); + return false; + } + + return true; +} + +void +UpnpNeighborExplorer::Close() +{ + delete discovery; + UpnpClientGlobalFinish(); +} + +NeighborExplorer::List +UpnpNeighborExplorer::GetList() const +{ + std::vector tmp; + + { + Error error; + if (!discovery->getDirServices(tmp, error)) + LogError(error); + } + + List result; + for (const auto &i : tmp) + result.emplace_front(i.GetURI(), i.getFriendlyName()); + return result; +} + +void +UpnpNeighborExplorer::FoundUPnP(const ContentDirectoryService &service) +{ + const NeighborInfo n(service.GetURI(), service.getFriendlyName()); + listener.FoundNeighbor(n); +} + +void +UpnpNeighborExplorer::LostUPnP(const ContentDirectoryService &service) +{ + const NeighborInfo n(service.GetURI(), service.getFriendlyName()); + listener.LostNeighbor(n); +} + +static NeighborExplorer * +upnp_neighbor_create(gcc_unused EventLoop &loop, + NeighborListener &listener, + gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new UpnpNeighborExplorer(listener); +} + +const NeighborPlugin upnp_neighbor_plugin = { + "upnp", + upnp_neighbor_create, +}; diff --git a/src/neighbor/plugins/UpnpNeighborPlugin.hxx b/src/neighbor/plugins/UpnpNeighborPlugin.hxx new file mode 100644 index 000000000..78e4ccf13 --- /dev/null +++ b/src/neighbor/plugins/UpnpNeighborPlugin.hxx @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_NEIGHBOR_UPNP_HXX +#define MPD_NEIGHBOR_UPNP_HXX + +struct NeighborPlugin; + +extern const NeighborPlugin upnp_neighbor_plugin; + +#endif -- cgit v1.2.3