aboutsummaryrefslogtreecommitdiffstats
path: root/src/db/upnp/upnpplib.cxx
diff options
context:
space:
mode:
authorJean-Francois Dockes <jf@dockes.org>2013-11-01 19:26:01 +0100
committerMax Kellermann <max@duempel.org>2014-01-09 20:56:00 +0100
commit406452f019f097bf52d8db529eabe8dd2d0e977a (patch)
treed70ce0b620cc97ed9d352f89063fa7cecffd6341 /src/db/upnp/upnpplib.cxx
parent12b139beafc191d02277e7ce97b4c59f7bb0c095 (diff)
downloadmpd-406452f019f097bf52d8db529eabe8dd2d0e977a.tar.gz
mpd-406452f019f097bf52d8db529eabe8dd2d0e977a.tar.xz
mpd-406452f019f097bf52d8db529eabe8dd2d0e977a.zip
UPnP database plugin
[mk: renamed source files, applied coding style, reduced bloat, using MPD's threading library, using MPD's error reporting and logging library and refactoring, fixed lots of bugs]
Diffstat (limited to '')
-rw-r--r--src/db/upnp/upnpplib.cxx144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/db/upnp/upnpplib.cxx b/src/db/upnp/upnpplib.cxx
new file mode 100644
index 000000000..27dd9557a
--- /dev/null
+++ b/src/db/upnp/upnpplib.cxx
@@ -0,0 +1,144 @@
+/*
+ * 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 "upnpplib.hxx"
+#include "Domain.hxx"
+#include "Util.hxx"
+#include "Log.hxx"
+
+#include <string>
+#include <sstream>
+#include <map>
+#include <vector>
+#include <set>
+
+#include <upnp/ixml.h>
+#include <upnp/upnpdebug.h>
+
+static LibUPnP *theLib;
+
+LibUPnP *
+LibUPnP::getLibUPnP(Error &error)
+{
+ if (theLib == nullptr)
+ theLib = new LibUPnP;
+
+ if (!theLib->ok()) {
+ error.Set(theLib->GetInitError());
+ return nullptr;
+ }
+
+ return theLib;
+}
+
+LibUPnP::LibUPnP()
+{
+ auto code = UpnpInit(0, 0);
+ if (code != UPNP_E_SUCCESS) {
+ init_error.Format(upnp_domain, code,
+ "UpnpInit() failed: %s",
+ UpnpGetErrorMessage(code));
+ return;
+ }
+
+ setMaxContentLength(2000*1024);
+#ifdef DEBUG
+ UpnpCloseLog();
+#endif
+
+ code = UpnpRegisterClient(o_callback, (void *)this, &m_clh);
+ if (code != UPNP_E_SUCCESS) {
+ init_error.Format(upnp_domain, code,
+ "UpnpRegisterClient() failed: %s",
+ UpnpGetErrorMessage(code));
+ return;
+ }
+
+ // Servers sometimes make error (e.g.: minidlna returns bad utf-8)
+ ixmlRelaxParser(1);
+}
+
+void LibUPnP::setMaxContentLength(int bytes)
+{
+ UpnpSetMaxContentLength(bytes);
+}
+
+bool LibUPnP::setLogFileName(const std::string& fn)
+{
+ const ScopeLock protect(m_mutex);
+
+ if (fn.empty()) {
+ UpnpCloseLog();
+ } else {
+ UpnpSetLogLevel(UPNP_INFO);
+ UpnpSetLogFileNames(fn.c_str(), fn.c_str());
+ int code = UpnpInitLog();
+ if (code != UPNP_E_SUCCESS) {
+ FormatError(upnp_domain, "UpnpInitLog() failed: %s",
+ UpnpGetErrorMessage(code));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+LibUPnP::registerHandler(Upnp_EventType et, Upnp_FunPtr handler, void *cookie)
+{
+ const ScopeLock protect(m_mutex);
+
+ if (handler == nullptr)
+ m_handlers.erase(et);
+ else
+ m_handlers.emplace(et, Handler(handler, cookie));
+}
+
+std::string
+LibUPnP::errAsString(const std::string& who, int code)
+{
+ std::ostringstream os;
+ os << who << " :" << code << ": " << UpnpGetErrorMessage(code);
+ return os.str();
+}
+
+int
+LibUPnP::o_callback(Upnp_EventType et, void* evp, void* cookie)
+{
+ LibUPnP *ulib = (LibUPnP *)cookie;
+ if (ulib == nullptr) {
+ // Because the asyncsearch calls uses a null cookie.
+ ulib = theLib;
+ }
+
+ auto it = ulib->m_handlers.find(et);
+ if (it != ulib->m_handlers.end()) {
+ (it->second.handler)(et, evp, it->second.cookie);
+ }
+ return UPNP_E_SUCCESS;
+}
+
+LibUPnP::~LibUPnP()
+{
+ int error = UpnpFinish();
+ if (error != UPNP_E_SUCCESS)
+ FormatError(upnp_domain, "UpnpFinish() failed: %s",
+ UpnpGetErrorMessage(error));
+}