@@ -240,41 +240,46 @@ PUPnP::terminate()
240
240
if (logger_) logger_->debug (" PUPnP: Instance {} terminated" , fmt::ptr (this ));
241
241
}
242
242
243
+ void
244
+ PUPnP::searchForDeviceAsync (const std::string& deviceType)
245
+ {
246
+ // Despite its name and the claim in the libupnp documentation that it "returns immediately",
247
+ // the UpnpSearchAsync function isn't really async. This is because it tries to send multiple
248
+ // copies of each search message and waits for a certain amount of time after sending each
249
+ // copy. The number of copies is given by the NUM_SSDP_COPY macro, whose default value is 2,
250
+ // and the waiting time is determined by the SSDP_PAUSE macro, whose default value is 100 (ms).
251
+ // If both IPv4 and IPv6 are enabled, then UpnpSearchAsync sends 3 distinct messages (2 for IPv6
252
+ // and 1 for IPv4), resulting in a total of 3 * 2 * 100 = 600 ms spent waiting by default.
253
+ // This is why we put the call to UpnpSearchAsync on its own thread.
254
+ dht::ThreadPool::io ().run ([w = weak_from_this (), deviceType] {
255
+ auto sthis = std::static_pointer_cast<PUPnP>(w.lock ());
256
+ if (!sthis)
257
+ return ;
258
+
259
+ auto err = UpnpSearchAsync (sthis->ctrlptHandle_ ,
260
+ SEARCH_TIMEOUT,
261
+ deviceType.c_str (),
262
+ sthis.get ());
263
+ if (err != UPNP_E_SUCCESS) {
264
+ if (sthis->logger_ )
265
+ sthis->logger_ ->warn (" PUPnP: Send search for {} failed. Error {:d}: {}" ,
266
+ deviceType,
267
+ err,
268
+ UpnpGetErrorMessage (err));
269
+ }
270
+ });
271
+ }
243
272
void
244
273
PUPnP::searchForDevices ()
245
274
{
246
275
if (logger_) logger_->debug (" PUPnP: Send IGD search request" );
247
276
248
277
// Send out search for multiple types of devices, as some routers may possibly
249
278
// only reply to one.
250
-
251
- auto err = UpnpSearchAsync (ctrlptHandle_, SEARCH_TIMEOUT, UPNP_ROOT_DEVICE, this );
252
- if (err != UPNP_E_SUCCESS) {
253
- if (logger_) logger_->warn (" PUPnP: Send search for UPNP_ROOT_DEVICE failed. Error {:d}: {}" ,
254
- err,
255
- UpnpGetErrorMessage (err));
256
- }
257
-
258
- err = UpnpSearchAsync (ctrlptHandle_, SEARCH_TIMEOUT, UPNP_IGD_DEVICE, this );
259
- if (err != UPNP_E_SUCCESS) {
260
- if (logger_) logger_->warn (" PUPnP: Send search for UPNP_IGD_DEVICE failed. Error {:d}: {}" ,
261
- err,
262
- UpnpGetErrorMessage (err));
263
- }
264
-
265
- err = UpnpSearchAsync (ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANIP_SERVICE, this );
266
- if (err != UPNP_E_SUCCESS) {
267
- if (logger_) logger_->warn (" PUPnP: Send search for UPNP_WANIP_SERVICE failed. Error {:d}: {}" ,
268
- err,
269
- UpnpGetErrorMessage (err));
270
- }
271
-
272
- err = UpnpSearchAsync (ctrlptHandle_, SEARCH_TIMEOUT, UPNP_WANPPP_SERVICE, this );
273
- if (err != UPNP_E_SUCCESS) {
274
- if (logger_) logger_->warn (" PUPnP: Send search for UPNP_WANPPP_SERVICE failed. Error {:d}: {}" ,
275
- err,
276
- UpnpGetErrorMessage (err));
277
- }
279
+ searchForDeviceAsync (UPNP_ROOT_DEVICE);
280
+ searchForDeviceAsync (UPNP_IGD_DEVICE);
281
+ searchForDeviceAsync (UPNP_WANIP_SERVICE);
282
+ searchForDeviceAsync (UPNP_WANPPP_SERVICE);
278
283
}
279
284
280
285
void
@@ -340,6 +345,7 @@ PUPnP::searchForIgd()
340
345
if (clientRegistered_) {
341
346
assert (initialized_);
342
347
searchForDevices ();
348
+ observer_->onIgdDiscoveryStarted ();
343
349
} else {
344
350
if (logger_) logger_->warn (" PUPnP: PUPNP not fully setup. Skipping the IGD search" );
345
351
}
0 commit comments