From d14fc35e433d4256805c059920bc07569ab07ebc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Fri, 6 Oct 2023 15:21:53 -0400
Subject: [PATCH] pupnp: fix hanging of UpnpDownloadXmlDoc in PUPnP

Sadly, this method is async, and can cause really long delay in
shutdown, but at least, avoid to call UPnPFinish before the end
of the download (else this method never returns)

GitLab: #8
Change-Id: I80df3da9b884b93a331aae738eae9a27be898fe2
---
 src/upnp/protocol/pupnp/pupnp.cpp | 12 ++++++++++++
 src/upnp/protocol/pupnp/pupnp.h   |  6 ++++++
 2 files changed, 18 insertions(+)

diff --git a/src/upnp/protocol/pupnp/pupnp.cpp b/src/upnp/protocol/pupnp/pupnp.cpp
index 8db0517..d07cc20 100644
--- a/src/upnp/protocol/pupnp/pupnp.cpp
+++ b/src/upnp/protocol/pupnp/pupnp.cpp
@@ -194,6 +194,9 @@ PUPnP::terminate(std::condition_variable& cv)
 
     clientRegistered_ = false;
     observer_ = nullptr;
+    std::unique_lock<std::mutex> lk(ongoingOpsMtx_);
+    destroying_ = true;
+    cvOngoing_.wait(lk, [&]() { return ongoingOps_ == 0; });
 
     UpnpUnRegisterClient(ctrlptHandle_);
 
@@ -779,6 +782,12 @@ void
 PUPnP::downLoadIgdDescription(const std::string& locationUrl)
 {
     if(logger_) logger_->debug("PUPnP: downLoadIgdDescription {}", locationUrl);
+    {
+        std::lock_guard<std::mutex> lk(ongoingOpsMtx_);
+        if (destroying_)
+            return;
+        ongoingOps_++;
+    }
     IXML_Document* doc_container_ptr = nullptr;
     int upnp_err = UpnpDownloadXmlDoc(locationUrl.c_str(), &doc_container_ptr);
 
@@ -794,6 +803,9 @@ PUPnP::downLoadIgdDescription(const std::string& locationUrl)
             }
         });
     }
+    std::lock_guard<std::mutex> lk(ongoingOpsMtx_);
+    ongoingOps_--;
+    cvOngoing_.notify_one();
 }
 
 void
diff --git a/src/upnp/protocol/pupnp/pupnp.h b/src/upnp/protocol/pupnp/pupnp.h
index 4c0ea78..7deb4fb 100644
--- a/src/upnp/protocol/pupnp/pupnp.h
+++ b/src/upnp/protocol/pupnp/pupnp.h
@@ -243,6 +243,12 @@ private:
 
     // Shutdown synchronization
     bool shutdownComplete_ {false};
+
+    // Count ongoing operations
+    std::mutex ongoingOpsMtx_;
+    std::condition_variable cvOngoing_;
+    int ongoingOps_ {0};
+    bool destroying_ {false};
 };
 
 } // namespace upnp
-- 
GitLab