- From ae107c22b946b60167d0d1da9630805cbb1af578 Mon Sep 17 00:00:00 2001
- From: Jean-Francois Dockes <jf@dockes.org>
- Date: Sun, 23 Aug 2020 14:22:21 +0200
- Subject: [PATCH] Modification to use npupnp instead of pupnp when the upnp
- meson option is set
-
- ---
- meson_options.txt | 5 +-
- .../plugins/upnp/ContentDirectoryService.cxx | 96 ++++++++++++++++++-
- src/lib/upnp/Action.hxx | 2 +
- src/lib/upnp/ContentDirectoryService.cxx | 35 ++++++-
- src/lib/upnp/Init.cxx | 6 +-
- src/lib/upnp/UniqueIxml.hxx | 6 +-
- src/lib/upnp/ixmlwrap.cxx | 8 +-
- src/lib/upnp/ixmlwrap.hxx | 4 +-
- src/lib/upnp/meson.build | 20 +++-
- 9 files changed, 169 insertions(+), 13 deletions(-)
-
- diff --git a/meson_options.txt b/meson_options.txt
- index 0a70ff3a3..d9fe0147d 100644
- --- a/meson_options.txt
- +++ b/meson_options.txt
- @@ -57,7 +57,10 @@ option('dsd', type: 'boolean', value: true, description: 'Support the DSD audio
- #
-
- option('database', type: 'boolean', value: true, description: 'enable support for the music database')
- -option('upnp', type: 'feature', description: 'UPnP client support')
- +option('upnp', type: 'combo',
- + choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
- + value: 'auto',
- + description: 'UPnP client support')
- option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
-
- #
- diff --git a/src/db/plugins/upnp/ContentDirectoryService.cxx b/src/db/plugins/upnp/ContentDirectoryService.cxx
- index 0cb94c42c..50405b9a0 100644
- --- a/src/db/plugins/upnp/ContentDirectoryService.cxx
- +++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
- @@ -18,7 +18,10 @@
- */
-
- #include "lib/upnp/ContentDirectoryService.hxx"
- -#include "lib/upnp/ixmlwrap.hxx"
- +#include "config.h"
- +#ifdef USING_PUPNP
- +# include "lib/upnp/ixmlwrap.hxx"
- +#endif
- #include "lib/upnp/UniqueIxml.hxx"
- #include "lib/upnp/Action.hxx"
- #include "Directory.hxx"
- @@ -27,6 +30,9 @@
- #include "util/ScopeExit.hxx"
- #include "util/StringFormat.hxx"
-
- +#include <algorithm>
- +
- +#ifdef USING_PUPNP
- static void
- ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
- {
- @@ -36,6 +42,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
-
- dirbuf.Parse(p);
- }
- +#endif
-
- inline void
- ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
- @@ -44,6 +51,7 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
- unsigned &didreadp,
- unsigned &totalp) const
- {
- +#ifdef USING_PUPNP
- // Some devices require an empty SortCriteria, else bad params
- IXML_Document *request =
- MakeActionHelper("Browse", m_serviceType.c_str(),
- @@ -79,6 +87,35 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
- totalp = ParseUnsigned(value);
-
- ReadResultTag(dirbuf, response);
- +#else
- + std::vector<std::pair<std::string, std::string>> actionParams{
- + {"ObjectID", objectId},
- + {"BrowseFlag", "BrowseDirectChildren"},
- + {"Filter", "*"},
- + {"SortCriteria", ""},
- + {"StartingIndex", StringFormat<32>("%u", offset).c_str()},
- + {"RequestedCount", StringFormat<32>("%u", count).c_str()}};
- + std::vector<std::pair<std::string, std::string>> responseData;
- + int errcode;
- + std::string errdesc;
- + int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
- + actionParams, responseData, &errcode, errdesc);
- + if (code != UPNP_E_SUCCESS)
- + throw FormatRuntimeError("UpnpSendAction() failed: %s",
- + UpnpGetErrorMessage(code));
- + const char *p = "";
- + didreadp = 0;
- + for (const auto &entry : responseData) {
- + if (entry.first == "Result") {
- + p = entry.second.c_str();
- + } else if (entry.first == "TotalMatches") {
- + totalp = ParseUnsigned(entry.second.c_str());
- + } else if (entry.first == "NumberReturned") {
- + didreadp = ParseUnsigned(entry.second.c_str());
- + }
- + }
- + dirbuf.Parse(p);
- +#endif
- }
-
- UPnPDirContent
- @@ -107,6 +144,7 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
- unsigned offset = 0, total = -1, count;
-
- do {
- +#ifdef USING_PUPNP
- UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
- "ContainerID", objectId,
- "SearchCriteria", ss,
- @@ -144,6 +182,36 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
- total = ParseUnsigned(value);
-
- ReadResultTag(dirbuf, response.get());
- +#else
- + std::vector<std::pair<std::string, std::string>> actionParams{
- + {"ContainerID", objectId},
- + {"SearchCriteria", ss},
- + {"Filter", "*"},
- + {"SortCriteria", ""},
- + {"StartingIndex", StringFormat<32>("%u", offset).c_str()},
- + {"RequestedCount", "0"}};
- + std::vector<std::pair<std::string, std::string>> responseData;
- + int errcode;
- + std::string errdesc;
- + int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Search",
- + actionParams, responseData, &errcode, errdesc);
- + if (code != UPNP_E_SUCCESS)
- + throw FormatRuntimeError("UpnpSendAction() failed: %s",
- + UpnpGetErrorMessage(code));
- + const char *p = "";
- + count = 0;
- + for (const auto &entry : responseData) {
- + if (entry.first == "Result") {
- + p = entry.second.c_str();
- + } else if (entry.first == "TotalMatches") {
- + total = ParseUnsigned(entry.second.c_str());
- + } else if (entry.first == "NumberReturned") {
- + count = ParseUnsigned(entry.second.c_str());
- + offset += count;
- + }
- + }
- + dirbuf.Parse(p);
- +#endif
- } while (count > 0 && offset < total);
-
- return dirbuf;
- @@ -153,6 +221,7 @@ UPnPDirContent
- ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
- const char *objectId) const
- {
- +#ifdef USING_PUPNP
- // Create request
- UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
- "ObjectID", objectId,
- @@ -176,4 +245,29 @@ ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
- UPnPDirContent dirbuf;
- ReadResultTag(dirbuf, response.get());
- return dirbuf;
- +#else
- + std::vector<std::pair<std::string, std::string>> actionParams{
- + {"ObjectID", objectId}, {"BrowseFlag", "BrowseMetadata"},
- + {"Filter", "*"}, {"SortCriteria", ""},
- + {"StartingIndex", "0"}, {"RequestedCount", "1"}};
- + std::vector<std::pair<std::string, std::string>> responseData;
- + int errcode;
- + std::string errdesc;
- + int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
- + actionParams, responseData, &errcode, errdesc);
- + if (code != UPNP_E_SUCCESS)
- + throw FormatRuntimeError("UpnpSendAction() failed: %s",
- + UpnpGetErrorMessage(code));
- + const char *p = "";
- + for (const auto &entry : responseData) {
- + if (entry.first == "Result") {
- + p = entry.second.c_str();
- + break;
- + }
- + }
- +
- + UPnPDirContent dirbuf;
- + dirbuf.Parse(p);
- + return dirbuf;
- +#endif
- }
- diff --git a/src/lib/upnp/Action.hxx b/src/lib/upnp/Action.hxx
- index 6de060560..19c423534 100644
- --- a/src/lib/upnp/Action.hxx
- +++ b/src/lib/upnp/Action.hxx
- @@ -38,6 +38,7 @@ CountNameValuePairs([[maybe_unused]] const char *name, [[maybe_unused]] const ch
- return 1 + CountNameValuePairs(args...);
- }
-
- +#ifdef USING_PUPNP
- /**
- * A wrapper for UpnpMakeAction() that counts the number of name/value
- * pairs and adds the nullptr sentinel.
- @@ -52,5 +53,6 @@ MakeActionHelper(const char *action_name, const char *service_type,
- args...,
- nullptr, nullptr);
- }
- +#endif
-
- #endif
- diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx
- index 56d1cf3aa..786bac6b1 100644
- --- a/src/lib/upnp/ContentDirectoryService.cxx
- +++ b/src/lib/upnp/ContentDirectoryService.cxx
- @@ -17,13 +17,21 @@
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
- +#include "config.h"
- +
- #include "ContentDirectoryService.hxx"
- -#include "UniqueIxml.hxx"
- #include "Device.hxx"
- -#include "ixmlwrap.hxx"
- -#include "util/UriRelative.hxx"
- -#include "util/RuntimeError.hxx"
- +#include "UniqueIxml.hxx"
- +#ifdef USING_PUPNP
- +# include "ixmlwrap.hxx"
- +#endif
- +#include "Action.hxx"
- #include "util/IterableSplitString.hxx"
- +#include "util/RuntimeError.hxx"
- +#include "util/UriRelative.hxx"
- +#include "util/UriUtil.hxx"
- +
- +#include <algorithm>
-
- #include <upnptools.h>
-
- @@ -50,6 +58,7 @@ ContentDirectoryService::~ContentDirectoryService() noexcept = default;
- std::forward_list<std::string>
- ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
- {
- +#ifdef USING_PUPNP
- UniqueIxmlDocument request(UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
- 0,
- nullptr, nullptr));
- @@ -68,6 +77,24 @@ ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
-
- const char *s = ixmlwrap::getFirstElementValue(response.get(),
- "SearchCaps");
- +#else
- + std::vector<std::pair<std::string, std::string>> responseData;
- + int errcode;
- + std::string errdesc;
- + auto code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
- + "GetSearchCapabilities", {}, responseData, &errcode,
- + errdesc);
- + if (code != UPNP_E_SUCCESS)
- + throw FormatRuntimeError("UpnpSendAction() failed: %s",
- + UpnpGetErrorMessage(code));
- + const char *s{nullptr};
- + for (auto &entry : responseData) {
- + if (entry.first == "SearchCaps") {
- + s = entry.second.c_str();
- + break;
- + }
- + }
- +#endif
- if (s == nullptr || *s == 0)
- return {};
-
- diff --git a/src/lib/upnp/Init.cxx b/src/lib/upnp/Init.cxx
- index def851f2c..d85b9a523 100644
- --- a/src/lib/upnp/Init.cxx
- +++ b/src/lib/upnp/Init.cxx
- @@ -23,7 +23,9 @@
- #include "util/RuntimeError.hxx"
-
- #include <upnptools.h>
- -#include <ixml.h>
- +#ifdef USING_PUPNP
- +# include <ixml.h>
- +#endif
-
- #include <cassert>
-
- @@ -44,8 +46,10 @@ DoInit()
-
- UpnpSetMaxContentLength(2000*1024);
-
- +#ifdef USING_PUPNP
- // Servers sometimes make error (e.g.: minidlna returns bad utf-8)
- ixmlRelaxParser(1);
- +#endif
- }
-
- void
- diff --git a/src/lib/upnp/UniqueIxml.hxx b/src/lib/upnp/UniqueIxml.hxx
- index 037e161b7..2ebc2c1c1 100644
- --- a/src/lib/upnp/UniqueIxml.hxx
- +++ b/src/lib/upnp/UniqueIxml.hxx
- @@ -20,9 +20,10 @@
- #ifndef MPD_UPNP_UNIQUE_XML_HXX
- #define MPD_UPNP_UNIQUE_XML_HXX
-
- -#include <ixml.h>
- +#ifdef USING_PUPNP
- +# include <ixml.h>
-
- -#include <memory>
- +# include <memory>
-
- struct UpnpIxmlDeleter {
- void operator()(IXML_Document *doc) noexcept {
- @@ -37,4 +38,5 @@ struct UpnpIxmlDeleter {
- typedef std::unique_ptr<IXML_Document, UpnpIxmlDeleter> UniqueIxmlDocument;
- typedef std::unique_ptr<IXML_NodeList, UpnpIxmlDeleter> UniqueIxmlNodeList;
-
- +#endif /* USING_PUPNP */
- #endif
- diff --git a/src/lib/upnp/ixmlwrap.cxx b/src/lib/upnp/ixmlwrap.cxx
- index f811b07a6..90e8d3155 100644
- --- a/src/lib/upnp/ixmlwrap.cxx
- +++ b/src/lib/upnp/ixmlwrap.cxx
- @@ -15,8 +15,11 @@
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- -#include "ixmlwrap.hxx"
- -#include "UniqueIxml.hxx"
- +#include "config.h"
- +
- +#ifdef USING_PUPNP
- +# include "ixmlwrap.hxx"
- +# include "UniqueIxml.hxx"
-
- namespace ixmlwrap {
-
- @@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc, const char *name) noexcept
- }
-
- } // namespace ixmlwrap
- +#endif
- diff --git a/src/lib/upnp/ixmlwrap.hxx b/src/lib/upnp/ixmlwrap.hxx
- index 2ef142ac7..25ac8695d 100644
- --- a/src/lib/upnp/ixmlwrap.hxx
- +++ b/src/lib/upnp/ixmlwrap.hxx
- @@ -17,7 +17,8 @@
- #ifndef _IXMLWRAP_H_INCLUDED_
- #define _IXMLWRAP_H_INCLUDED_
-
- -#include <ixml.h>
- +#ifdef USING_PUPNP
- +# include <ixml.h>
-
- namespace ixmlwrap {
- /**
- @@ -30,4 +31,5 @@ namespace ixmlwrap {
-
- }
-
- +#endif /* USING_PUPNP */
- #endif /* _IXMLWRAP_H_INCLUDED_ */
- diff --git a/src/lib/upnp/meson.build b/src/lib/upnp/meson.build
- index f7570eb1c..bdc248e6c 100644
- --- a/src/lib/upnp/meson.build
- +++ b/src/lib/upnp/meson.build
- @@ -1,4 +1,22 @@
- -upnp_dep = dependency('libupnp', version: '>= 1.8', required: get_option('upnp'))
- +upnp_option = get_option('upnp')
- +
- +if upnp_option == 'auto'
- + upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)
- + conf.set('USING_PUPNP', upnp_dep.found())
- + if not upnp_dep.found()
- + upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
- + endif
- +elif upnp_option == 'pupnp'
- + upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)
- + conf.set('USING_PUPNP', true)
- +elif upnp_option == 'npupnp'
- + upnp_dep = dependency('libnpupnp', required: true)
- + conf.set('USING_PUPNP', false)
- +elif upnp_option == 'disabled'
- + upnp_dep = dependency('', required: false)
- + subdir_done()
- +endif
- +
- conf.set('ENABLE_UPNP', upnp_dep.found())
- if not upnp_dep.found()
- subdir_done()
|