02d255673a954678b2b98995487f16e405173a71
[feed/packages.git] / sound / mpd / patches / 020-npupnp.patch
1 From 61df54155a3cb1846e6bf15e4f007ec8d623de63 Mon Sep 17 00:00:00 2001
2 From: Jean-Francois Dockes <jf@dockes.org>
3 Date: Sun, 23 Aug 2020 14:22:21 +0200
4 Subject: [PATCH] Modification to use npupnp instead of pupnp when the upnp
5 meson option is set
6
7 ---
8 meson_options.txt | 5 +-
9 .../plugins/upnp/ContentDirectoryService.cxx | 101 ++++++++++++++++++
10 src/lib/upnp/Action.hxx | 2 +
11 src/lib/upnp/ClientInit.cxx | 12 +--
12 src/lib/upnp/Compat.hxx | 4 +-
13 src/lib/upnp/ContentDirectoryService.cxx | 25 +++++
14 src/lib/upnp/Init.cxx | 4 +
15 src/lib/upnp/UniqueIxml.hxx | 2 +
16 src/lib/upnp/ixmlwrap.cxx | 4 +
17 src/lib/upnp/ixmlwrap.hxx | 2 +
18 src/lib/upnp/meson.build | 20 +++-
19 11 files changed, 170 insertions(+), 11 deletions(-)
20
21 diff --git a/meson_options.txt b/meson_options.txt
22 index d17ac1ca8..da90ccfd8 100644
23 --- a/meson_options.txt
24 +++ b/meson_options.txt
25 @@ -54,7 +54,10 @@ option('dsd', type: 'boolean', value: true, description: 'Support the DSD audio
26 #
27
28 option('database', type: 'boolean', value: true, description: 'enable support for the music database')
29 -option('upnp', type: 'feature', description: 'UPnP client support')
30 +option('upnp', type: 'combo',
31 + choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
32 + value: 'auto',
33 + description: 'UPnP client support')
34 option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
35
36 #
37 diff --git a/src/db/plugins/upnp/ContentDirectoryService.cxx b/src/db/plugins/upnp/ContentDirectoryService.cxx
38 index 99893d89d..29d58ca23 100644
39 --- a/src/db/plugins/upnp/ContentDirectoryService.cxx
40 +++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
41 @@ -18,7 +18,10 @@
42 */
43
44 #include "lib/upnp/ContentDirectoryService.hxx"
45 +#include "config.h"
46 +#ifdef USING_PUPNP
47 #include "lib/upnp/ixmlwrap.hxx"
48 +#endif
49 #include "lib/upnp/UniqueIxml.hxx"
50 #include "lib/upnp/Action.hxx"
51 #include "Directory.hxx"
52 @@ -28,8 +31,11 @@
53 #include "util/ScopeExit.hxx"
54 #include "util/StringFormat.hxx"
55
56 +#include <algorithm>
57 +
58 #include <stdio.h>
59
60 +#ifdef USING_PUPNP
61 static void
62 ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
63 {
64 @@ -39,6 +45,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
65
66 dirbuf.Parse(p);
67 }
68 +#endif
69
70 inline void
71 ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
72 @@ -47,6 +54,7 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
73 unsigned &didreadp,
74 unsigned &totalp) const
75 {
76 +#ifdef USING_PUPNP
77 // Some devices require an empty SortCriteria, else bad params
78 IXML_Document *request =
79 MakeActionHelper("Browse", m_serviceType.c_str(),
80 @@ -82,6 +90,37 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
81 totalp = ParseUnsigned(value);
82
83 ReadResultTag(dirbuf, response);
84 +#else
85 + std::vector<std::pair<std::string, std::string> > actionParams{
86 + { "ObjectID", objectId },
87 + { "BrowseFlag", "BrowseDirectChildren" },
88 + { "Filter", "*" },
89 + { "SortCriteria", "" },
90 + { "StartingIndex", StringFormat<32>("%u", offset).c_str() },
91 + { "RequestedCount", StringFormat<32>("%u", count).c_str() }
92 + };
93 + std::vector<std::pair<std::string, std::string> > responseData;
94 + int errcode;
95 + std::string errdesc;
96 + int code =
97 + UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
98 + actionParams, responseData, &errcode, errdesc);
99 + if (code != UPNP_E_SUCCESS)
100 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
101 + UpnpGetErrorMessage(code));
102 + const char *p = "";
103 + didreadp = 0;
104 + for (const auto &entry : responseData) {
105 + if (entry.first == "Result") {
106 + p = entry.second.c_str();
107 + } else if (entry.first == "TotalMatches") {
108 + totalp = ParseUnsigned(entry.second.c_str());
109 + } else if (entry.first == "NumberReturned") {
110 + didreadp = ParseUnsigned(entry.second.c_str());
111 + }
112 + }
113 + dirbuf.Parse(p);
114 +#endif
115 }
116
117 UPnPDirContent
118 @@ -110,6 +149,7 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
119 unsigned offset = 0, total = -1, count;
120
121 do {
122 +#ifdef USING_PUPNP
123 UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
124 "ContainerID", objectId,
125 "SearchCriteria", ss,
126 @@ -147,6 +187,39 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
127 total = ParseUnsigned(value);
128
129 ReadResultTag(dirbuf, response.get());
130 +#else
131 + std::vector<std::pair<std::string, std::string> > actionParams{
132 + { "ContainerID", objectId },
133 + { "SearchCriteria", ss },
134 + { "Filter", "*" },
135 + { "SortCriteria", "" },
136 + { "StartingIndex",
137 + StringFormat<32>("%u", offset).c_str() },
138 + { "RequestedCount", "0" }
139 + };
140 + std::vector<std::pair<std::string, std::string> > responseData;
141 + int errcode;
142 + std::string errdesc;
143 + int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
144 + "Search", actionParams, responseData,
145 + &errcode, errdesc);
146 + if (code != UPNP_E_SUCCESS)
147 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
148 + UpnpGetErrorMessage(code));
149 + const char *p = "";
150 + count = 0;
151 + for (const auto &entry : responseData) {
152 + if (entry.first == "Result") {
153 + p = entry.second.c_str();
154 + } else if (entry.first == "TotalMatches") {
155 + total = ParseUnsigned(entry.second.c_str());
156 + } else if (entry.first == "NumberReturned") {
157 + count = ParseUnsigned(entry.second.c_str());
158 + offset += count;
159 + }
160 + }
161 + dirbuf.Parse(p);
162 +#endif
163 } while (count > 0 && offset < total);
164
165 return dirbuf;
166 @@ -156,6 +229,7 @@ UPnPDirContent
167 ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
168 const char *objectId) const
169 {
170 +#ifdef USING_PUPNP
171 // Create request
172 UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
173 "ObjectID", objectId,
174 @@ -179,4 +253,31 @@ ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
175 UPnPDirContent dirbuf;
176 ReadResultTag(dirbuf, response.get());
177 return dirbuf;
178 +#else
179 + std::vector<std::pair<std::string, std::string> > actionParams{
180 + { "ObjectID", objectId }, { "BrowseFlag", "BrowseMetadata" },
181 + { "Filter", "*" }, { "SortCriteria", "" },
182 + { "StartingIndex", "0" }, { "RequestedCount", "1" }
183 + };
184 + std::vector<std::pair<std::string, std::string> > responseData;
185 + int errcode;
186 + std::string errdesc;
187 + int code =
188 + UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
189 + actionParams, responseData, &errcode, errdesc);
190 + if (code != UPNP_E_SUCCESS)
191 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
192 + UpnpGetErrorMessage(code));
193 + const char *p = "";
194 + for (const auto &entry : responseData) {
195 + if (entry.first == "Result") {
196 + p = entry.second.c_str();
197 + break;
198 + }
199 + }
200 +
201 + UPnPDirContent dirbuf;
202 + dirbuf.Parse(p);
203 + return dirbuf;
204 +#endif
205 }
206 diff --git a/src/lib/upnp/Action.hxx b/src/lib/upnp/Action.hxx
207 index 49ed75198..4ecf4cb06 100644
208 --- a/src/lib/upnp/Action.hxx
209 +++ b/src/lib/upnp/Action.hxx
210 @@ -38,6 +38,7 @@ CountNameValuePairs(gcc_unused const char *name, gcc_unused const char *value,
211 return 1 + CountNameValuePairs(args...);
212 }
213
214 +#ifdef USING_PUPNP
215 /**
216 * A wrapper for UpnpMakeAction() that counts the number of name/value
217 * pairs and adds the nullptr sentinel.
218 @@ -52,5 +53,6 @@ MakeActionHelper(const char *action_name, const char *service_type,
219 args...,
220 nullptr, nullptr);
221 }
222 +#endif
223
224 #endif
225 diff --git a/src/lib/upnp/ClientInit.cxx b/src/lib/upnp/ClientInit.cxx
226 index 23ba9cade..54b677fa2 100644
227 --- a/src/lib/upnp/ClientInit.cxx
228 +++ b/src/lib/upnp/ClientInit.cxx
229 @@ -31,14 +31,12 @@ static Mutex upnp_client_init_mutex;
230 static unsigned upnp_client_ref;
231 static UpnpClient_Handle upnp_client_handle;
232
233 -static int
234 -UpnpClientCallback(Upnp_EventType et,
235 -#if UPNP_VERSION >= 10800
236 - const
237 +static int UpnpClientCallback(Upnp_EventType et,
238 +#if 1
239 + const
240 #endif
241 - void *evp,
242 - void *cookie) noexcept
243 -{
244 + void *evp,
245 + void *cookie) noexcept {
246 if (cookie == nullptr)
247 /* this is the cookie passed to UpnpRegisterClient();
248 but can this ever happen? Will libupnp ever invoke
249 diff --git a/src/lib/upnp/Compat.hxx b/src/lib/upnp/Compat.hxx
250 index 7fba1d83b..b9a4d7cf3 100644
251 --- a/src/lib/upnp/Compat.hxx
252 +++ b/src/lib/upnp/Compat.hxx
253 @@ -22,14 +22,14 @@
254
255 #include <upnp.h>
256
257 -#if UPNP_VERSION < 10800
258 +#if 0
259 /* emulate the libupnp 1.8 API with older versions */
260
261 using UpnpDiscovery = Upnp_Discovery;
262
263 #endif
264
265 -#if UPNP_VERSION < 10624
266 +#if 0
267 #include "util/Compiler.h"
268
269 gcc_pure
270 diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx
271 index ae514c717..eed28b41a 100644
272 --- a/src/lib/upnp/ContentDirectoryService.cxx
273 +++ b/src/lib/upnp/ContentDirectoryService.cxx
274 @@ -17,15 +17,21 @@
275 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
276 */
277
278 +#include "config.h"
279 +
280 #include "ContentDirectoryService.hxx"
281 #include "UniqueIxml.hxx"
282 #include "Device.hxx"
283 +#ifdef USING_PUPNP
284 #include "ixmlwrap.hxx"
285 +#endif
286 #include "Action.hxx"
287 #include "util/UriUtil.hxx"
288 #include "util/RuntimeError.hxx"
289 #include "util/SplitString.hxx"
290
291 +#include <algorithm>
292 +
293 ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
294 const UPnPService &service) noexcept
295 :m_actionURL(uri_apply_base(service.controlURL, device.URLBase)),
296 @@ -51,6 +57,7 @@ ContentDirectoryService::~ContentDirectoryService() noexcept
297 std::forward_list<std::string>
298 ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
299 {
300 +#ifdef USING_PUPNP
301 UniqueIxmlDocument request(UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
302 0,
303 nullptr, nullptr));
304 @@ -69,6 +76,24 @@ ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
305
306 const char *s = ixmlwrap::getFirstElementValue(response.get(),
307 "SearchCaps");
308 +#else
309 + std::vector<std::pair<std::string, std::string> > responseData;
310 + int errcode;
311 + std::string errdesc;
312 + auto code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
313 + "GetSearchCapabilities", {}, responseData,
314 + &errcode, errdesc);
315 + if (code != UPNP_E_SUCCESS)
316 + throw FormatRuntimeError("UpnpSendAction() failed: %s",
317 + UpnpGetErrorMessage(code));
318 + const char *s{ nullptr };
319 + for (auto &entry : responseData) {
320 + if (entry.first == "SearchCaps") {
321 + s = entry.second.c_str();
322 + break;
323 + }
324 + }
325 +#endif
326 if (s == nullptr || *s == 0)
327 /* we could just "return {}" here, but GCC 5 doesn't
328 understand that */
329 diff --git a/src/lib/upnp/Init.cxx b/src/lib/upnp/Init.cxx
330 index 7ad4d565a..10510402a 100644
331 --- a/src/lib/upnp/Init.cxx
332 +++ b/src/lib/upnp/Init.cxx
333 @@ -23,7 +23,9 @@
334
335 #include <upnp.h>
336 #include <upnptools.h>
337 +#ifdef USING_PUPNP
338 #include <ixml.h>
339 +#endif
340
341 #include <assert.h>
342
343 @@ -44,8 +46,10 @@ DoInit()
344
345 UpnpSetMaxContentLength(2000*1024);
346
347 +#ifdef USING_PUPNP
348 // Servers sometimes make error (e.g.: minidlna returns bad utf-8)
349 ixmlRelaxParser(1);
350 +#endif
351 }
352
353 void
354 diff --git a/src/lib/upnp/UniqueIxml.hxx b/src/lib/upnp/UniqueIxml.hxx
355 index 2ff2afa62..8a0ea0a1f 100644
356 --- a/src/lib/upnp/UniqueIxml.hxx
357 +++ b/src/lib/upnp/UniqueIxml.hxx
358 @@ -20,6 +20,7 @@
359 #ifndef MPD_UPNP_UNIQUE_XML_HXX
360 #define MPD_UPNP_UNIQUE_XML_HXX
361
362 +#ifdef USING_PUPNP
363 #include <ixml.h>
364
365 #include <memory>
366 @@ -37,4 +38,5 @@ struct UpnpIxmlDeleter {
367 typedef std::unique_ptr<IXML_Document, UpnpIxmlDeleter> UniqueIxmlDocument;
368 typedef std::unique_ptr<IXML_NodeList, UpnpIxmlDeleter> UniqueIxmlNodeList;
369
370 +#endif /* USING_PUPNP */
371 #endif
372 diff --git a/src/lib/upnp/ixmlwrap.cxx b/src/lib/upnp/ixmlwrap.cxx
373 index 4e44f35a6..c7798e557 100644
374 --- a/src/lib/upnp/ixmlwrap.cxx
375 +++ b/src/lib/upnp/ixmlwrap.cxx
376 @@ -15,6 +15,9 @@
377 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
378 */
379
380 +#include "config.h"
381 +
382 +#ifdef USING_PUPNP
383 #include "ixmlwrap.hxx"
384 #include "UniqueIxml.hxx"
385
386 @@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc, const char *name) noexcept
387 }
388
389 }
390 +#endif
391 diff --git a/src/lib/upnp/ixmlwrap.hxx b/src/lib/upnp/ixmlwrap.hxx
392 index 6713d59bd..4b01801f7 100644
393 --- a/src/lib/upnp/ixmlwrap.hxx
394 +++ b/src/lib/upnp/ixmlwrap.hxx
395 @@ -17,6 +17,7 @@
396 #ifndef _IXMLWRAP_H_INCLUDED_
397 #define _IXMLWRAP_H_INCLUDED_
398
399 +#ifdef USING_PUPNP
400 #include <ixml.h>
401
402 #include <string>
403 @@ -32,4 +33,5 @@ namespace ixmlwrap {
404
405 }
406
407 +#endif /* USING_PUPNP */
408 #endif /* _IXMLWRAP_H_INCLUDED_ */
409 diff --git a/src/lib/upnp/meson.build b/src/lib/upnp/meson.build
410 index 9e16f7319..bdc248e6c 100644
411 --- a/src/lib/upnp/meson.build
412 +++ b/src/lib/upnp/meson.build
413 @@ -1,4 +1,22 @@
414 -upnp_dep = dependency('libupnp', required: get_option('upnp'))
415 +upnp_option = get_option('upnp')
416 +
417 +if upnp_option == 'auto'
418 + upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)
419 + conf.set('USING_PUPNP', upnp_dep.found())
420 + if not upnp_dep.found()
421 + upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
422 + endif
423 +elif upnp_option == 'pupnp'
424 + upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)
425 + conf.set('USING_PUPNP', true)
426 +elif upnp_option == 'npupnp'
427 + upnp_dep = dependency('libnpupnp', required: true)
428 + conf.set('USING_PUPNP', false)
429 +elif upnp_option == 'disabled'
430 + upnp_dep = dependency('', required: false)
431 + subdir_done()
432 +endif
433 +
434 conf.set('ENABLE_UPNP', upnp_dep.found())
435 if not upnp_dep.found()
436 subdir_done()