Switch to unified view

a/libupnpp/control/discovery.cxx b/libupnpp/control/discovery.cxx
...
...
28
28
29
#include <upnp/upnp.h>
29
#include <upnp/upnp.h>
30
#include <upnp/upnptools.h>
30
#include <upnp/upnptools.h>
31
31
32
#include "libupnpp/upnpp_p.hxx"
32
#include "libupnpp/upnpp_p.hxx"
33
#include "libupnpp/upnpputils.hxx"
33
#include "libupnpp/workqueue.hxx"
34
#include "libupnpp/workqueue.hxx"
34
#include "libupnpp/upnpplib.hxx"
35
#include "libupnpp/upnpplib.hxx"
35
#include "libupnpp/log.hxx"
36
#include "libupnpp/log.hxx"
36
#include "description.hxx"
37
#include "description.hxx"
37
#include "discovery.hxx"
38
#include "discovery.hxx"
38
39
39
namespace UPnPClient {
40
namespace UPnPClient {
41
42
static UPnPDeviceDirectory *theDevDir;
40
43
41
//#undef LOCAL_LOGINC
44
//#undef LOCAL_LOGINC
42
//#define LOCAL_LOGINC 3
45
//#define LOCAL_LOGINC 3
43
46
44
static string cluDiscoveryToStr(const struct Upnp_Discovery *disco)
47
static string cluDiscoveryToStr(const struct Upnp_Discovery *disco)
...
...
73
    bool alive;
76
    bool alive;
74
    string url;
77
    string url;
75
    string deviceId;
78
    string deviceId;
76
    int expires; // Seconds valid
79
    int expires; // Seconds valid
77
};
80
};
81
82
// The workqueue on which callbacks from libupnp (cluCallBack()) queue
83
// discovered object descriptors for processing by our dedicated
84
// thread.
78
static WorkQueue<DiscoveredTask*> discoveredQueue("DiscoveredQueue");
85
static WorkQueue<DiscoveredTask*> discoveredQueue("DiscoveredQueue");
79
86
80
// This gets called in a libupnp thread context for all asynchronous
87
// This gets called in a libupnp thread context for all asynchronous
81
// events which we asked for.
88
// events which we asked for.
82
// Example: ContentDirectories appearing and disappearing from the network
89
// Example: ContentDirectories appearing and disappearing from the network
83
// We queue a task for our worker thread(s)
90
// We queue a task for our worker thread(s)
84
// It seems that this can get called by several threads. We have a
91
// It seems that this can get called by several threads. We have a
85
// mutex just for clarifying the message printing, the workqueue is
92
// mutex just for clarifying the message printing, the workqueue is
86
// mt-safe of course.
93
// mt-safe of course.
87
static PTMutexInit cblock;
88
static int cluCallBack(Upnp_EventType et, void* evp, void*)
94
static int cluCallBack(Upnp_EventType et, void* evp, void*)
89
{
95
{
96
    static PTMutexInit cblock;
90
    PTMutexLocker lock(cblock);
97
    PTMutexLocker lock(cblock);
91
    LOGDEB1("discovery:cluCallBack: " << LibUPnP::evTypeAsString(et) << endl);
98
    LOGDEB1("discovery:cluCallBack: " << LibUPnP::evTypeAsString(et) << endl);
92
99
93
    switch (et) {
100
    switch (et) {
94
    case UPNP_DISCOVERY_SEARCH_RESULT:
101
    case UPNP_DISCOVERY_SEARCH_RESULT:
...
...
128
    }
135
    }
129
136
130
    return UPNP_E_SUCCESS;
137
    return UPNP_E_SUCCESS;
131
}
138
}
132
139
133
// Descriptor for one device found on the network.
140
// Our client can set up functions to be called when we process a new device.
141
// This is used during startup, when the pool is not yet complete, to enable
142
// finding and listing devices as soon as they appear.
143
static vector<UPnPDeviceDirectory::Visitor> o_callbacks;
144
static PTMutexInit o_callbacks_mutex;
145
146
unsigned int UPnPDeviceDirectory::addCallback(UPnPDeviceDirectory::Visitor v)
147
{
148
    PTMutexLocker lock(o_callbacks_mutex);
149
    o_callbacks.push_back(v);
150
    return o_callbacks.size() - 1;
151
}
152
153
void UPnPDeviceDirectory::delCallback(unsigned int idx)
154
{
155
    PTMutexLocker lock(o_callbacks_mutex);
156
    if (idx >= o_callbacks.size())
157
        return;
158
    o_callbacks.erase(o_callbacks.begin() + idx);
159
}
160
161
// Descriptor kept in the device pool for each device found on the network.
134
class DeviceDescriptor {
162
class DeviceDescriptor {
135
public:
163
public:
136
    DeviceDescriptor(const string& url, const string& description,
164
    DeviceDescriptor(const string& url, const string& description,
137
                     time_t last, int exp)
165
                     time_t last, int exp)
138
        : device(url, description), last_seen(last), expires(exp+20)
166
        : device(url, description), last_seen(last), expires(exp+20)
...
...
207
                continue;
235
                continue;
208
            }
236
            }
209
            LOGDEB1("discoExplorer: found id [" << tsk->deviceId  << "]" 
237
            LOGDEB1("discoExplorer: found id [" << tsk->deviceId  << "]" 
210
                    << " name " << d.device.friendlyName 
238
                    << " name " << d.device.friendlyName 
211
                    << " devtype " << d.device.deviceType << endl);
239
                    << " devtype " << d.device.deviceType << endl);
240
            {
212
            PTMutexLocker lock(o_pool.m_mutex);
241
                PTMutexLocker lock(o_pool.m_mutex);
213
            //LOGDEB1("discoExplorer: inserting device id "<< tsk->deviceId << 
242
                //LOGDEB1("discoExplorer: inserting device id "<< tsk->deviceId
214
            //        " description: " << endl << d.device.dump() << endl);
243
                // <<  " description: " << endl << d.device.dump() << endl);
215
            o_pool.m_devices[tsk->deviceId] = d;
244
                o_pool.m_devices[tsk->deviceId] = d;
245
            }
246
            {
247
                PTMutexLocker lock(o_callbacks_mutex);
248
                for (auto& cb: o_callbacks) {
249
                    cb(d.device, UPnPServiceDesc());
250
                }
251
            }
216
        }
252
        }
217
        delete tsk;
253
        delete tsk;
218
    }
254
    }
219
}
255
}
220
256
...
...
250
// This means that you have to wait for the specified period before
286
// This means that you have to wait for the specified period before
251
// the results are complete.
287
// the results are complete.
252
UPnPDeviceDirectory::UPnPDeviceDirectory(time_t search_window)
288
UPnPDeviceDirectory::UPnPDeviceDirectory(time_t search_window)
253
    : m_ok(false), m_searchTimeout(search_window), m_lastSearch(0)
289
    : m_ok(false), m_searchTimeout(search_window), m_lastSearch(0)
254
{
290
{
291
    addCallback(std::bind(&UPnPDeviceDirectory::deviceFound, this, _1, _2));
292
255
    if (!discoveredQueue.start(1, discoExplorer, 0)) {
293
    if (!discoveredQueue.start(1, discoExplorer, 0)) {
256
        m_reason = "Discover work queue start failed";
294
        m_reason = "Discover work queue start failed";
257
        return;
295
        return;
258
    }
296
    }
259
    pthread_yield();
297
    pthread_yield();
...
...
294
    }
332
    }
295
    m_lastSearch = time(0);
333
    m_lastSearch = time(0);
296
    return true;
334
    return true;
297
}
335
}
298
336
299
static UPnPDeviceDirectory *theDevDir;
300
301
UPnPDeviceDirectory *UPnPDeviceDirectory::getTheDir(time_t search_window)
337
UPnPDeviceDirectory *UPnPDeviceDirectory::getTheDir(time_t search_window)
302
{
338
{
303
    if (theDevDir == 0)
339
    if (theDevDir == 0)
304
        theDevDir = new UPnPDeviceDirectory(search_window);
340
        theDevDir = new UPnPDeviceDirectory(search_window);
305
    if (theDevDir && !theDevDir->ok())
341
    if (theDevDir && !theDevDir->ok())
...
...
323
bool UPnPDeviceDirectory::traverse(UPnPDeviceDirectory::Visitor visit)
359
bool UPnPDeviceDirectory::traverse(UPnPDeviceDirectory::Visitor visit)
324
{
360
{
325
    //LOGDEB("UPnPDeviceDirectory::traverse" << endl);
361
    //LOGDEB("UPnPDeviceDirectory::traverse" << endl);
326
    if (m_ok == false)
362
    if (m_ok == false)
327
        return false;
363
        return false;
328
329
    if (getRemainingDelay() > 0)
330
        sleep(getRemainingDelay());
364
    int secs = getRemainingDelay();
365
    if (secs > 0)
366
        sleep(secs);
331
367
332
    // Has locking, do it before our own lock
368
    // Has locking, do it before our own lock
333
    expireDevices();
369
    expireDevices();
334
370
335
    PTMutexLocker lock(o_pool.m_mutex);
371
    PTMutexLocker lock(o_pool.m_mutex);
...
...
341
        }
377
        }
342
    }
378
    }
343
    return true;
379
    return true;
344
}
380
}
345
381
382
static PTMutexInit devWaitLock;
383
static pthread_cond_t devWaitCond = PTHREAD_COND_INITIALIZER;
384
385
bool UPnPDeviceDirectory::deviceFound(const UPnPDeviceDesc&, 
386
                                      const UPnPServiceDesc&)
387
{
388
    PTMutexLocker lock(devWaitLock);
389
    pthread_cond_broadcast(&devWaitCond);
390
    return true;
391
}
392
393
bool UPnPDeviceDirectory::getDevBySelector(bool cmp(const UPnPDeviceDesc& ddesc,
394
                                                    const string&), 
395
                                           const string& value,
396
                                           UPnPDeviceDesc& ddesc)
397
{
398
    // Has locking, do it before our own lock
399
    expireDevices();
400
401
    struct timespec wkuptime;
402
    long long nanos = getRemainingDelay() * 1000*1000*1000;
403
    clock_gettime(CLOCK_REALTIME, &wkuptime);
404
    UPnPP::timespec_addnanos(&wkuptime, nanos);
405
    do {
406
        PTMutexLocker lock(devWaitLock);
407
        {
408
            PTMutexLocker lock(o_pool.m_mutex);
409
            for (auto& dde : o_pool.m_devices) {
410
                if (!cmp(dde.second.device, value)) {
411
                    ddesc = dde.second.device;
412
                    return true;
413
                }
414
            }
415
        }
416
417
        if (nanos > 0) {
418
            pthread_cond_timedwait(&devWaitCond, lock.getMutex(), &wkuptime);
419
        }
420
    } while (getRemainingDelay() > 0);
421
    return false;
422
}
423
424
static bool cmpFName(const UPnPDeviceDesc& ddesc, const string& fname)
425
{
426
    return ddesc.friendlyName.compare(fname);
427
}
428
429
bool UPnPDeviceDirectory::getDevByFName(const string& fname, 
430
                                        UPnPDeviceDesc& ddesc)
431
{
432
    return getDevBySelector(cmpFName, fname, ddesc);
433
}
434
435
static bool cmpUDN(const UPnPDeviceDesc& ddesc, const string& value)
436
{
437
    return ddesc.UDN.compare(value);
438
}
439
440
bool UPnPDeviceDirectory::getDevByUDN(const string& value, 
441
                                      UPnPDeviceDesc& ddesc)
442
{
443
    return getDevBySelector(cmpUDN, value, ddesc);
444
}
445
446
447
346
} // namespace UPnPClient
448
} // namespace UPnPClient
347
449