From a13f3588f78e9ffda5e915f44cbf1957f12513c4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Fri, 13 Mar 2020 09:19:04 +0100 Subject: [PATCH] Quick changes for working with NPUPNP (Rebased and made default) Signed-off-by: Rosen Penev --- CMakeLists.txt | 43 +++++++++++++++++------- src/action_request.cc | 11 +++++- src/device_description_handler.cc | 4 +++ src/file_request_handler.cc | 4 +++ src/iohandler/file_io_handler.cc | 1 - src/iohandler/io_handler.cc | 1 - src/iohandler/mem_io_handler.cc | 1 - src/serve_request_handler.cc | 8 +++++ src/server.cc | 8 +++++ src/transcoding/transcode_ext_handler.cc | 1 - src/upnp_cds.cc | 11 ++++++ src/upnp_cm.cc | 11 ++++++ src/upnp_mrreg.cc | 7 +++- src/url_request_handler.cc | 5 ++- src/util/upnp_clients.cc | 12 +++++++ src/util/upnp_headers.cc | 12 +++++++ src/web/web_request_handler.cc | 4 +++ 17 files changed, 124 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b6db993..b23dad57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ if (CONAN_EXPORTED) endif() set(CMAKE_VERBOSE_MAKEFILE off CACHE BOOL "Show verbose build commands") +set(WITH_NPUPNP 0 CACHE BOOL "Use npupnp instead of pupnp") set(WITH_MAGIC 1 CACHE BOOL "Use libmagic to identify file mime types") set(WITH_MYSQL 0 CACHE BOOL "Store media information in MySQL DB") set(WITH_CURL 1 CACHE BOOL "CURL required for online services") @@ -303,23 +304,39 @@ add_definitions(${LFS_DEFINITIONS}) add_compile_options(${LFS_COMPILE_OPTIONS}) target_link_libraries(libgerbera ${LFS_LIBRARIES}) -find_package (pupnp "1.12.1" REQUIRED) +if (WITH_NPUPNP) + find_package(PkgConfig QUIET) + pkg_check_modules (NPUPNP QUIET libnpupnp>=4.0.11) + if (NOT NPUPNP_FOUND) + find_package (NPUPNP REQUIRED) + endif() + if (NPUPNP_FOUND) + include_directories (${NPUPNP_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES npupnp) + add_definitions(-DUSING_NPUPNP) + target_link_libraries (libgerbera ${NPUPNP_LIBRARIES}) + else() + message(FATAL_ERROR "libnpupnp not found") + endif() +else() + find_package (pupnp "1.12.1" REQUIRED) -set(CMAKE_REQUIRED_LIBRARIES pupnp::pupnp) + set(CMAKE_REQUIRED_LIBRARIES pupnp::pupnp) -check_cxx_symbol_exists(UPNP_ENABLE_IPV6 "upnpconfig.h" UPNP_HAS_IPV6) -if (NOT UPNP_HAS_IPV6) - message(FATAL_ERROR "Gerbera requires libupnp with IPv6 support.") -endif() + check_cxx_symbol_exists(UPNP_ENABLE_IPV6 "upnpconfig.h" UPNP_HAS_IPV6) + if (NOT UPNP_HAS_IPV6) + message(FATAL_ERROR "Gerbera requires libupnp with IPv6 support.") + endif() -check_cxx_symbol_exists(UPNP_MINISERVER_REUSEADDR "upnpconfig.h" UPNP_HAS_REUSEADDR) -if (NOT UPNP_HAS_REUSEADDR) - message(WARNING [=[ -!! It is strongly recommended to build libupnp with --enable-reuseaddr !! -Without this option Gerbera will be unable to restart with the same port number.]=]) -endif() + check_cxx_symbol_exists(UPNP_MINISERVER_REUSEADDR "upnpconfig.h" UPNP_HAS_REUSEADDR) + if (NOT UPNP_HAS_REUSEADDR) + message(WARNING [=[ + !! It is strongly recommended to build libupnp with --enable-reuseaddr !! + Without this option Gerbera will be unable to restart with the same port number.]=]) + endif() -target_link_libraries (libgerbera pupnp::pupnp) + target_link_libraries (libgerbera pupnp::pupnp) +endif() find_package(fmt REQUIRED) target_link_libraries(libgerbera fmt::fmt) diff --git a/src/action_request.cc b/src/action_request.cc index fab0e910..5677e61e 100644 --- a/src/action_request.cc +++ b/src/action_request.cc @@ -65,10 +65,14 @@ std::string ActionRequest::getServiceID() const std::unique_ptr ActionRequest::getRequest() const { - DOMString cxml = ixmlPrintDocument(UpnpActionRequest_get_ActionRequest(upnp_request)); auto request = std::make_unique(); +#if defined(USING_NPUPNP) + auto ret = request->load_string(upnp_request->xmlAction.c_str()); +#else + DOMString cxml = ixmlPrintDocument(UpnpActionRequest_get_ActionRequest(upnp_request)); auto ret = request->load_string(cxml); ixmlFreeDOMString(cxml); +#endif if (ret.status != pugi::xml_parse_status::status_ok) throw_std_runtime_error("Unable to parse ixml"); @@ -94,6 +98,10 @@ void ActionRequest::update() std::string xml = buf.str(); log_debug("ActionRequest::update(): {}", xml.c_str()); +#if defined(USING_NPUPNP) + UpnpActionRequest_set_xmlResponse(upnp_request, xml); + UpnpActionRequest_set_ErrCode(upnp_request, errCode); +#else IXML_Document* result = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &result); @@ -105,6 +113,7 @@ void ActionRequest::update() UpnpActionRequest_set_ActionResult(upnp_request, result); UpnpActionRequest_set_ErrCode(upnp_request, errCode); } +#endif } else { // ok, here there can be two cases // either the function below already did set an error code, diff --git a/src/device_description_handler.cc b/src/device_description_handler.cc index 6aca745e..cf2e8015 100644 --- a/src/device_description_handler.cc +++ b/src/device_description_handler.cc @@ -45,7 +45,11 @@ void DeviceDescriptionHandler::getInfo(const char* filename, UpnpFileInfo* info) { // We should be able to do the generation here, but libupnp doesnt support the request cookies yet UpnpFileInfo_set_FileLength(info, -1); +#if defined(USING_NPUPNP) UpnpFileInfo_set_ContentType(info, "application/xml"); +#else + UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString("application/xml")); +#endif UpnpFileInfo_set_IsReadable(info, 1); UpnpFileInfo_set_IsDirectory(info, 0); } diff --git a/src/file_request_handler.cc b/src/file_request_handler.cc index cfa3eaed..915e411b 100644 --- a/src/file_request_handler.cc +++ b/src/file_request_handler.cc @@ -238,7 +238,11 @@ void FileRequestHandler::getInfo(const char* filename, UpnpFileInfo* info) UpnpFileInfo_set_LastModified(info, statbuf.st_mtime); UpnpFileInfo_set_IsDirectory(info, S_ISDIR(statbuf.st_mode)); +#if defined(USING_NPUPNP) + UpnpFileInfo_set_ContentType(info, mimeType); +#else UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str())); +#endif headers->writeHeaders(info); diff --git a/src/iohandler/file_io_handler.cc b/src/iohandler/file_io_handler.cc index 7e239250..b023e85b 100644 --- a/src/iohandler/file_io_handler.cc +++ b/src/iohandler/file_io_handler.cc @@ -32,7 +32,6 @@ #include "file_io_handler.h" // API #include -#include #include #include "cds_objects.h" diff --git a/src/iohandler/io_handler.cc b/src/iohandler/io_handler.cc index f9789425..1153ce6b 100644 --- a/src/iohandler/io_handler.cc +++ b/src/iohandler/io_handler.cc @@ -31,7 +31,6 @@ #include "io_handler.h" // API -#include #include #include "server.h" diff --git a/src/iohandler/mem_io_handler.cc b/src/iohandler/mem_io_handler.cc index 5574a16d..223746ef 100644 --- a/src/iohandler/mem_io_handler.cc +++ b/src/iohandler/mem_io_handler.cc @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/src/serve_request_handler.cc b/src/serve_request_handler.cc index 59f37252..42d07e94 100644 --- a/src/serve_request_handler.cc +++ b/src/serve_request_handler.cc @@ -94,7 +94,11 @@ void ServeRequestHandler::getInfo(const char* filename, UpnpFileInfo* info) UpnpFileInfo_set_IsReadable(info, 0); } +#if defined(USING_NPUPNP) + UpnpFileInfo_set_ContentType(info, mimetype); +#else UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimetype.c_str())); +#endif } else { throw_std_runtime_error("Not a regular file: " + path); } @@ -158,7 +162,11 @@ std::unique_ptr ServeRequestHandler::open(const char* filename, } +#if defined(USING_NPUPNP) + info->content_type = mimetype; +#else info->content_type = ixmlCloneDOMString(mimetype.c_str()); +#endif */ } else { throw_std_runtime_error("Not a regular file: " + path); diff --git a/src/server.cc b/src/server.cc index a83c28cd..d4ce3e51 100644 --- a/src/server.cc +++ b/src/server.cc @@ -393,9 +393,17 @@ int Server::handleUpnpClientEvent(Upnp_EventType eventType, const void* event) case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_SEARCH_RESULT: { auto d_event = reinterpret_cast(event); +#if defined(USING_NPUPNP) + const char* userAgent = UpnpDiscovery_get_Os_cstr(d_event); +#else const char* userAgent = UpnpString_get_String(UpnpDiscovery_get_Os(d_event)); +#endif const struct sockaddr_storage* destAddr = UpnpDiscovery_get_DestAddr(d_event); +#if defined(USING_NPUPNP) + const char* location = UpnpDiscovery_get_Location_cstr(d_event); +#else const char* location = UpnpString_get_String(UpnpDiscovery_get_Location(d_event)); +#endif Clients::addClientByDiscovery(destAddr, userAgent, location); break; diff --git a/src/transcoding/transcode_ext_handler.cc b/src/transcoding/transcode_ext_handler.cc index 67ee79d9..1da59ea2 100644 --- a/src/transcoding/transcode_ext_handler.cc +++ b/src/transcoding/transcode_ext_handler.cc @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/src/upnp_cds.cc b/src/upnp_cds.cc index 12ffeea2..5c2e1043 100644 --- a/src/upnp_cds.cc +++ b/src/upnp_cds.cc @@ -284,6 +284,11 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptrprint(buf, "", 0); std::string xml = buf.str(); +#if defined(USING_NPUPNP) + UpnpAcceptSubscriptionXML( + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(), + DESC_CDS_SERVICE_ID, xml, request->getSubscriptionID().c_str()); +#else IXML_Document* event = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &event); if (err != IXML_SUCCESS) { @@ -295,6 +300,7 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptrgetSubscriptionID().c_str()); ixmlDocument_free(event); +#endif log_debug("end"); } @@ -313,6 +319,10 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe propset->print(buf, "", 0); std::string xml = buf.str(); +#if defined(USING_NPUPNP) + UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(), + DESC_CDS_SERVICE_ID, xml); +#else IXML_Document* event = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &event); if (err != IXML_SUCCESS) { @@ -325,6 +335,7 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe DESC_CDS_SERVICE_ID, event); ixmlDocument_free(event); +#endif log_debug("end"); } diff --git a/src/upnp_cm.cc b/src/upnp_cm.cc index aa608480..d7ab40cf 100644 --- a/src/upnp_cm.cc +++ b/src/upnp_cm.cc @@ -127,6 +127,11 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr< propset->print(buf, "", 0); std::string xml = buf.str(); +#if defined(USING_NPUPNP) + UpnpAcceptSubscriptionXML( + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(), + DESC_CM_SERVICE_ID, xml, request->getSubscriptionID().c_str()); +#else IXML_Document* event = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &event); if (err != IXML_SUCCESS) { @@ -138,6 +143,7 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr< DESC_CM_SERVICE_ID, event, request->getSubscriptionID().c_str()); ixmlDocument_free(event); +#endif } void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceProtocol_CSV) @@ -150,6 +156,10 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP propset->print(buf, "", 0); std::string xml = buf.str(); +#if defined(USING_NPUPNP) + UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(), + DESC_CM_SERVICE_ID, xml); +#else IXML_Document* event = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &event); if (err != IXML_SUCCESS) { @@ -162,4 +172,5 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP DESC_CM_SERVICE_ID, event); ixmlDocument_free(event); +#endif } diff --git a/src/upnp_mrreg.cc b/src/upnp_mrreg.cc index 16eefaed..ecb49025 100644 --- a/src/upnp_mrreg.cc +++ b/src/upnp_mrreg.cc @@ -34,7 +34,6 @@ #include #include "config/config_manager.h" -#include "ixml.h" #include "server.h" #include "storage/storage.h" #include "upnp_xml.h" @@ -120,6 +119,11 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptrprint(buf, "", 0); std::string xml = buf.str(); +#if defined(USING_NPUPNP) + UpnpAcceptSubscriptionXML( + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(), + DESC_MRREG_SERVICE_ID, xml, request->getSubscriptionID().c_str()); +#else IXML_Document* event = nullptr; int err = ixmlParseBufferEx(xml.c_str(), &event); if (err != IXML_SUCCESS) { @@ -131,6 +135,7 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptrgetSubscriptionID().c_str()); ixmlDocument_free(event); +#endif } // TODO: FIXME diff --git a/src/url_request_handler.cc b/src/url_request_handler.cc index f2a99c94..7de2227d 100644 --- a/src/url_request_handler.cc +++ b/src/url_request_handler.cc @@ -32,7 +32,6 @@ #ifdef HAVE_CURL #include "url_request_handler.h" // API -#include #include #include "config/config_manager.h" @@ -138,7 +137,11 @@ void URLRequestHandler::getInfo(const char* filename, UpnpFileInfo* info) // ixmlCloneDOMString(header.c_str())); // } +#if defined(USING_NPUPNP) + UpnpFileInfo_set_ContentType(info, mimeType); +#else UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str())); +#endif log_debug("web_get_info(): end"); /// \todo transcoding for get_info diff --git a/src/util/upnp_clients.cc b/src/util/upnp_clients.cc index 6fd40de2..28f0fb16 100644 --- a/src/util/upnp_clients.cc +++ b/src/util/upnp_clients.cc @@ -262,6 +262,17 @@ bool Clients::getInfoByType(const std::string& match, ClientMatchType type, cons bool Clients::downloadDescription(const std::string& location, std::unique_ptr& xml) { +#if defined(USING_NPUPNP) + std::string description, ct; + int errCode = UpnpDownloadUrlItem(location, description, ct); + if (errCode != UPNP_E_SUCCESS) { + log_debug("Error obtaining client description from {} -- error = {}", location, errCode); + return false; + } + const char* cxml = description.c_str(); + xml = std::make_unique(); + auto ret = xml->load_string(cxml); +#else IXML_Document* descDoc = nullptr; int errCode = UpnpDownloadXmlDoc(location.c_str(), &descDoc); if (errCode != UPNP_E_SUCCESS) { @@ -275,6 +286,7 @@ bool Clients::downloadDescription(const std::string& location, std::unique_ptr

11299) #include #else #include #endif +#endif #include #include "common.h" @@ -101,18 +103,27 @@ void Headers::writeHeaders(UpnpFileInfo* fileInfo) const if (headers == nullptr) return; +#if defined(USING_NPUPNP) + std::copy(headers->begin(), headers->end(), std::back_inserter(fileInfo->response_headers)); +#else auto head = const_cast(UpnpFileInfo_get_ExtraHeadersList(fileInfo)); for (const auto& iter : *headers) { UpnpExtraHeaders* h = UpnpExtraHeaders_new(); UpnpExtraHeaders_set_resp(h, formatHeader(iter, false).c_str()); UpnpListInsert(head, UpnpListEnd(head), const_cast(UpnpExtraHeaders_get_node(h))); } +#endif } std::unique_ptr> Headers::readHeaders(UpnpFileInfo* fileInfo) { auto ret = std::make_unique>(); +#if defined(USING_NPUPNP) + for (const auto& entry : fileInfo->request_headers) { + ret->insert(entry); + } +#else auto head = const_cast(UpnpFileInfo_get_ExtraHeadersList(fileInfo)); UpnpListIter pos; for (pos = UpnpListBegin(head); pos != UpnpListEnd(head); pos = UpnpListNext(head, pos)) { @@ -121,6 +132,7 @@ std::unique_ptr> Headers::readHeaders(UpnpFil auto add = parseHeader(header); ret->insert(add); } +#endif return ret; } diff --git a/src/web/web_request_handler.cc b/src/web/web_request_handler.cc index 60e2d028..117dcbfa 100644 --- a/src/web/web_request_handler.cc +++ b/src/web/web_request_handler.cc @@ -112,7 +112,11 @@ void WebRequestHandler::getInfo(const char* filename, UpnpFileInfo* info) std::string mimetype = (returnType == "xml") ? MIMETYPE_XML : MIMETYPE_JSON; std::string contentType = mimetype + "; charset=" + DEFAULT_INTERNAL_CHARSET; +#if defined(USING_NPUPNP) + UpnpFileInfo_set_ContentType(info, contentType); +#else UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(contentType.c_str())); +#endif Headers headers; headers.addHeader(std::string { "Cache-Control" }, std::string { "no-cache, must-revalidate" }); headers.writeHeaders(info);