diff --git a/Makefile.am b/Makefile.am index c9b0e05ba..0d8cde097 100644 --- a/Makefile.am +++ b/Makefile.am @@ -222,6 +222,7 @@ UPNP_SOURCES = \ src/lib/upnp/Discovery.cxx src/lib/upnp/Discovery.hxx \ src/lib/upnp/Domain.cxx src/lib/upnp/Domain.hxx \ src/lib/upnp/ixmlwrap.cxx src/lib/upnp/ixmlwrap.hxx \ + src/lib/upnp/Callback.hxx \ src/lib/upnp/upnpplib.cxx src/lib/upnp/upnpplib.hxx \ src/lib/upnp/Util.cxx src/lib/upnp/Util.hxx \ src/lib/upnp/WorkQueue.hxx \ diff --git a/src/lib/upnp/Callback.hxx b/src/lib/upnp/Callback.hxx new file mode 100644 index 000000000..85daf0a7e --- /dev/null +++ b/src/lib/upnp/Callback.hxx @@ -0,0 +1,46 @@ +/* + * 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_UPNP_CALLBACK_HXX +#define MPD_UPNP_CALLBACK_HXX + +#include + +/** + * A class that is supposed to be used for libupnp asynchronous + * callbacks. + */ +class UpnpCallback { +public: + /** + * Pass this value as "cookie" pointer to libupnp asynchronous + * functions. + */ + void *GetUpnpCookie() { + return this; + } + + static UpnpCallback &FromUpnpCookie(void *cookie) { + return *(UpnpCallback *)cookie; + } + + virtual int Invoke(Upnp_EventType et, void *evp) = 0; +}; + +#endif diff --git a/src/lib/upnp/Discovery.cxx b/src/lib/upnp/Discovery.cxx index da32372ba..ce512bdde 100644 --- a/src/lib/upnp/Discovery.cxx +++ b/src/lib/upnp/Discovery.cxx @@ -184,8 +184,8 @@ UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco) // thread context. // Example: ContentDirectories appearing and disappearing from the network // We queue a task for our worker thread(s) -inline int -UPnPDeviceDirectory::cluCallBack(Upnp_EventType et, void *evp) +int +UPnPDeviceDirectory::Invoke(Upnp_EventType et, void *evp) { switch (et) { case UPNP_DISCOVERY_SEARCH_RESULT: @@ -254,10 +254,6 @@ UPnPDeviceDirectory::Start(Error &error) return false; } - lib->SetHandler([this](Upnp_EventType type, void *event){ - cluCallBack(type, event); - }); - return search(error); } @@ -271,7 +267,7 @@ UPnPDeviceDirectory::search(Error &error) // We search both for device and service just in case. int code = UpnpSearchAsync(lib->getclh(), m_searchTimeout, - ContentDirectorySType, lib); + ContentDirectorySType, GetUpnpCookie()); if (code != UPNP_E_SUCCESS) { error.Format(upnp_domain, code, "UpnpSearchAsync() failed: %s", @@ -280,7 +276,7 @@ UPnPDeviceDirectory::search(Error &error) } code = UpnpSearchAsync(lib->getclh(), m_searchTimeout, - MediaServerDType, lib); + MediaServerDType, GetUpnpCookie()); if (code != UPNP_E_SUCCESS) { error.Format(upnp_domain, code, "UpnpSearchAsync() failed: %s", diff --git a/src/lib/upnp/Discovery.hxx b/src/lib/upnp/Discovery.hxx index 3208f8727..1a126edfd 100644 --- a/src/lib/upnp/Discovery.hxx +++ b/src/lib/upnp/Discovery.hxx @@ -20,6 +20,7 @@ #ifndef _UPNPPDISC_H_X_INCLUDED_ #define _UPNPPDISC_H_X_INCLUDED_ +#include "Callback.hxx" #include "Device.hxx" #include "WorkQueue.hxx" #include "thread/Mutex.hxx" @@ -46,7 +47,7 @@ public: * We are only interested in MediaServers with a ContentDirectory service * for now, but this could be made more general, by removing the filtering. */ -class UPnPDeviceDirectory { +class UPnPDeviceDirectory final : UpnpCallback { /** * Each appropriate discovery event (executing in a libupnp thread * context) queues the following task object for processing by the @@ -154,6 +155,9 @@ private: int OnAlive(Upnp_Discovery *disco); int OnByeBye(Upnp_Discovery *disco); int cluCallBack(Upnp_EventType et, void *evp); + + /* virtual methods from class UpnpCallback */ + virtual int Invoke(Upnp_EventType et, void *evp) override; }; diff --git a/src/lib/upnp/upnpplib.cxx b/src/lib/upnp/upnpplib.cxx index 475447dee..452c033d5 100644 --- a/src/lib/upnp/upnpplib.cxx +++ b/src/lib/upnp/upnpplib.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "upnpplib.hxx" +#include "Callback.hxx" #include "Domain.hxx" #include "Log.hxx" @@ -37,7 +38,7 @@ LibUPnP::LibUPnP() UpnpSetMaxContentLength(2000*1024); - code = UpnpRegisterClient(o_callback, (void *)this, &m_clh); + code = UpnpRegisterClient(o_callback, nullptr, &m_clh); if (code != UPNP_E_SUCCESS) { init_error.Format(upnp_domain, code, "UpnpRegisterClient() failed: %s", @@ -52,12 +53,14 @@ LibUPnP::LibUPnP() int LibUPnP::o_callback(Upnp_EventType et, void* evp, void* cookie) { - LibUPnP *ulib = (LibUPnP *)cookie; + if (cookie == nullptr) + /* this is the cookie passed to UpnpRegisterClient(); + but can this ever happen? Will libupnp ever invoke + the registered callback without that cookie? */ + return UPNP_E_SUCCESS; - if (ulib->handler) - ulib->handler(et, evp); - - return UPNP_E_SUCCESS; + UpnpCallback &callback = UpnpCallback::FromUpnpCookie(cookie); + return callback.Invoke(et, evp); } LibUPnP::~LibUPnP() diff --git a/src/lib/upnp/upnpplib.hxx b/src/lib/upnp/upnpplib.hxx index 6759aa16d..cd1762ec4 100644 --- a/src/lib/upnp/upnpplib.hxx +++ b/src/lib/upnp/upnpplib.hxx @@ -24,17 +24,11 @@ #include -#include - /** Our link to libupnp. Initialize and keep the handle around */ class LibUPnP { - typedef std::function Handler; - Error init_error; UpnpClient_Handle m_clh; - Handler handler; - static int o_callback(Upnp_EventType, void *, void *); public: @@ -56,11 +50,6 @@ public: return init_error; } - template - void SetHandler(T &&_handler) { - handler = std::forward(_handler); - } - UpnpClient_Handle getclh() { return m_clh;