From 6f81bb4b097ce96a5c81d22d48896df8f8551c2f Mon Sep 17 00:00:00 2001
From: Max Audron <audron@cocaine.farm>
Date: Mon, 8 Nov 2021 22:56:34 +0100
Subject: [PATCH] upnp: add option to configure interface for db plugin

Add an option to the UPnP database plugin to configure which interface
is used by upnp to discover servers.

upnp by default selects the first interface that is not loopback, which
in some cases might not be the desired interface. For example if wanting
to access a DLNA server over a VPN connection.

The "interface" option can now be set to the name of the desired
interface to achieve this.

The default behaviour remains unchanged.
---
 doc/plugins.rst                            |  9 +++++++++
 src/db/plugins/upnp/UpnpDatabasePlugin.cxx | 14 +++++++++-----
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/doc/plugins.rst b/doc/plugins.rst
index d1022f163..5216a9b4d 100644
--- a/doc/plugins.rst
+++ b/doc/plugins.rst
@@ -61,6 +61,15 @@ upnp
 
 Provides access to UPnP media servers.
 
+.. list-table::
+   :widths: 20 80
+   :header-rows: 1
+
+   * - Setting
+     - Description
+   * - **interface**
+     - Interface used to discover media servers. Decided by upnp if left unconfigured.
+
 Storage plugins
 ===============
 
diff --git a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
index 86d3fe99a..318ec9a5c 100644
--- a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
+++ b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
@@ -39,6 +39,7 @@
 #include "util/ConstBuffer.hxx"
 #include "util/RecursiveMap.hxx"
 #include "util/SplitString.hxx"
+#include "config/Block.hxx"
 
 #include <cassert>
 #include <string>
@@ -76,10 +77,13 @@ class UpnpDatabase : public Database {
 	UpnpClient_Handle handle;
 	UPnPDeviceDirectory *discovery;
 
+	const char* interface;
+
 public:
-	explicit UpnpDatabase(EventLoop &_event_loop) noexcept
+	explicit UpnpDatabase(EventLoop &_event_loop, const ConfigBlock &block) noexcept
 		:Database(upnp_db_plugin),
-		 event_loop(_event_loop) {}
+		 event_loop(_event_loop),
+		 interface(block.GetBlockValue("interface", nullptr)) {}
 
 	static DatabasePtr Create(EventLoop &main_event_loop,
 				  EventLoop &io_event_loop,
@@ -147,15 +151,15 @@ private:
 DatabasePtr
 UpnpDatabase::Create(EventLoop &, EventLoop &io_event_loop,
 		     [[maybe_unused]] DatabaseListener &listener,
-		     const ConfigBlock &) noexcept
+		     const ConfigBlock &block) noexcept
 {
-	return std::make_unique<UpnpDatabase>(io_event_loop);
+	return std::make_unique<UpnpDatabase>(io_event_loop, block);;
 }
 
 void
 UpnpDatabase::Open()
 {
-	handle = UpnpClientGlobalInit(nullptr);
+	handle = UpnpClientGlobalInit(interface);
 
 	discovery = new UPnPDeviceDirectory(event_loop, handle);
 	try {