db/upnp/Discovery: move callbacks and data structures into class
Eliminate global variables.
This commit is contained in:
parent
aa64a5328e
commit
e2812f722d
|
@ -19,20 +19,14 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Discovery.hxx"
|
#include "Discovery.hxx"
|
||||||
#include "Device.hxx"
|
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
#include "ContentDirectoryService.hxx"
|
#include "ContentDirectoryService.hxx"
|
||||||
#include "WorkQueue.hxx"
|
|
||||||
#include "upnpplib.hxx"
|
#include "upnpplib.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
|
||||||
|
|
||||||
#include <upnp/upnp.h>
|
|
||||||
#include <upnp/upnptools.h>
|
#include <upnp/upnptools.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
// The service type string we are looking for.
|
// The service type string we are looking for.
|
||||||
static const char *const ContentDirectorySType = "urn:schemas-upnp-org:service:ContentDirectory:1";
|
static const char *const ContentDirectorySType = "urn:schemas-upnp-org:service:ContentDirectory:1";
|
||||||
|
|
||||||
|
@ -57,64 +51,14 @@ isMSDevice(const char *st)
|
||||||
return memcmp(MediaServerDType, st, sz) == 0;
|
return memcmp(MediaServerDType, st, sz) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
inline void
|
||||||
* Each appropriate discovery event (executing in a libupnp thread
|
UPnPDeviceDirectory::discoExplorer()
|
||||||
* context) queues the following task object for processing by the
|
|
||||||
* discovery thread.
|
|
||||||
*/
|
|
||||||
struct DiscoveredTask {
|
|
||||||
bool alive;
|
|
||||||
std::string url;
|
|
||||||
std::string deviceId;
|
|
||||||
int expires; // Seconds valid
|
|
||||||
|
|
||||||
DiscoveredTask(bool _alive, const Upnp_Discovery *disco)
|
|
||||||
: alive(_alive), url(disco->Location),
|
|
||||||
deviceId(disco->DeviceId),
|
|
||||||
expires(disco->Expires) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
static WorkQueue<DiscoveredTask *> discoveredQueue("DiscoveredQueue");
|
|
||||||
|
|
||||||
// Descriptor for one device having a Content Directory service found
|
|
||||||
// on the network.
|
|
||||||
class ContentDirectoryDescriptor {
|
|
||||||
public:
|
|
||||||
ContentDirectoryDescriptor(const std::string &url,
|
|
||||||
const std::string &description,
|
|
||||||
time_t last, int exp)
|
|
||||||
:device(url, description), last_seen(last), expires(exp+20) {}
|
|
||||||
UPnPDevice device;
|
|
||||||
time_t last_seen;
|
|
||||||
int expires; // seconds valid
|
|
||||||
};
|
|
||||||
|
|
||||||
// A ContentDirectoryPool holds the characteristics of the servers
|
|
||||||
// currently on the network.
|
|
||||||
// The map is referenced by deviceId (==UDN)
|
|
||||||
// The class is instanciated as a static (unenforced) singleton.
|
|
||||||
class ContentDirectoryPool {
|
|
||||||
public:
|
|
||||||
Mutex m_mutex;
|
|
||||||
std::map<std::string, ContentDirectoryDescriptor> m_directories;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ContentDirectoryPool contentDirectories;
|
|
||||||
|
|
||||||
// Worker routine for the discovery queue. Get messages about devices
|
|
||||||
// appearing and disappearing, and update the directory pool
|
|
||||||
// accordingly.
|
|
||||||
static void *
|
|
||||||
discoExplorer(void *)
|
|
||||||
{
|
{
|
||||||
auto &mutex = contentDirectories.m_mutex;
|
|
||||||
auto &directories = contentDirectories.m_directories;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
DiscoveredTask *tsk = 0;
|
DiscoveredTask *tsk = 0;
|
||||||
if (!discoveredQueue.take(tsk)) {
|
if (!discoveredQueue.take(tsk)) {
|
||||||
discoveredQueue.workerExit();
|
discoveredQueue.workerExit();
|
||||||
return (void*)1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
@ -156,8 +100,16 @@ discoExplorer(void *)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
void *
|
||||||
OnAlive(Upnp_Discovery *disco)
|
UPnPDeviceDirectory::discoExplorer(void *ctx)
|
||||||
|
{
|
||||||
|
UPnPDeviceDirectory &directory = *(UPnPDeviceDirectory *)ctx;
|
||||||
|
directory.discoExplorer();
|
||||||
|
return (void*)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int
|
||||||
|
UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
|
||||||
{
|
{
|
||||||
if (isMSDevice(disco->DeviceType) ||
|
if (isMSDevice(disco->DeviceType) ||
|
||||||
isCDService(disco->ServiceType)) {
|
isCDService(disco->ServiceType)) {
|
||||||
|
@ -169,8 +121,8 @@ OnAlive(Upnp_Discovery *disco)
|
||||||
return UPNP_E_SUCCESS;
|
return UPNP_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
inline int
|
||||||
OnByeBye(Upnp_Discovery *disco)
|
UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isMSDevice(disco->DeviceType) ||
|
if (isMSDevice(disco->DeviceType) ||
|
||||||
|
@ -187,8 +139,8 @@ OnByeBye(Upnp_Discovery *disco)
|
||||||
// thread context.
|
// thread context.
|
||||||
// Example: ContentDirectories appearing and disappearing from the network
|
// Example: ContentDirectories appearing and disappearing from the network
|
||||||
// We queue a task for our worker thread(s)
|
// We queue a task for our worker thread(s)
|
||||||
static int
|
inline int
|
||||||
cluCallBack(Upnp_EventType et, void *evp)
|
UPnPDeviceDirectory::cluCallBack(Upnp_EventType et, void *evp)
|
||||||
{
|
{
|
||||||
switch (et) {
|
switch (et) {
|
||||||
case UPNP_DISCOVERY_SEARCH_RESULT:
|
case UPNP_DISCOVERY_SEARCH_RESULT:
|
||||||
|
@ -215,8 +167,7 @@ cluCallBack(Upnp_EventType et, void *evp)
|
||||||
void
|
void
|
||||||
UPnPDeviceDirectory::expireDevices()
|
UPnPDeviceDirectory::expireDevices()
|
||||||
{
|
{
|
||||||
const ScopeLock protect(contentDirectories.m_mutex);
|
const ScopeLock protect(mutex);
|
||||||
auto &directories = contentDirectories.m_directories;
|
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
bool didsomething = false;
|
bool didsomething = false;
|
||||||
|
|
||||||
|
@ -235,14 +186,16 @@ UPnPDeviceDirectory::expireDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
UPnPDeviceDirectory::UPnPDeviceDirectory(LibUPnP *_lib)
|
UPnPDeviceDirectory::UPnPDeviceDirectory(LibUPnP *_lib)
|
||||||
:lib(_lib), m_searchTimeout(2), m_lastSearch(0)
|
:lib(_lib),
|
||||||
|
discoveredQueue("DiscoveredQueue"),
|
||||||
|
m_searchTimeout(2), m_lastSearch(0)
|
||||||
{
|
{
|
||||||
if (!discoveredQueue.start(1, discoExplorer, 0)) {
|
if (!discoveredQueue.start(1, discoExplorer, this)) {
|
||||||
error.Set(upnp_domain, "Discover work queue start failed");
|
error.Set(upnp_domain, "Discover work queue start failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lib->SetHandler([](Upnp_EventType type, void *event){
|
lib->SetHandler([this](Upnp_EventType type, void *event){
|
||||||
cluCallBack(type, event);
|
cluCallBack(type, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -288,8 +241,7 @@ UPnPDeviceDirectory::getDirServices(std::vector<ContentDirectoryService> &out)
|
||||||
// Has locking, do it before our own lock
|
// Has locking, do it before our own lock
|
||||||
expireDevices();
|
expireDevices();
|
||||||
|
|
||||||
const ScopeLock protect(contentDirectories.m_mutex);
|
const ScopeLock protect(mutex);
|
||||||
auto &directories = contentDirectories.m_directories;
|
|
||||||
|
|
||||||
for (auto dit = directories.begin();
|
for (auto dit = directories.begin();
|
||||||
dit != directories.end(); dit++) {
|
dit != directories.end(); dit++) {
|
||||||
|
|
|
@ -20,9 +20,16 @@
|
||||||
#ifndef _UPNPPDISC_H_X_INCLUDED_
|
#ifndef _UPNPPDISC_H_X_INCLUDED_
|
||||||
#define _UPNPPDISC_H_X_INCLUDED_
|
#define _UPNPPDISC_H_X_INCLUDED_
|
||||||
|
|
||||||
|
#include "Device.hxx"
|
||||||
|
#include "WorkQueue.hxx"
|
||||||
|
#include "thread/Mutex.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
|
||||||
|
#include <upnp/upnp.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
@ -36,10 +43,46 @@ class ContentDirectoryService;
|
||||||
* for now, but this could be made more general, by removing the filtering.
|
* for now, but this could be made more general, by removing the filtering.
|
||||||
*/
|
*/
|
||||||
class UPnPDeviceDirectory {
|
class UPnPDeviceDirectory {
|
||||||
|
/**
|
||||||
|
* Each appropriate discovery event (executing in a libupnp thread
|
||||||
|
* context) queues the following task object for processing by the
|
||||||
|
* discovery thread.
|
||||||
|
*/
|
||||||
|
struct DiscoveredTask {
|
||||||
|
bool alive;
|
||||||
|
std::string url;
|
||||||
|
std::string deviceId;
|
||||||
|
int expires; // Seconds valid
|
||||||
|
|
||||||
|
DiscoveredTask(bool _alive, const Upnp_Discovery *disco)
|
||||||
|
: alive(_alive), url(disco->Location),
|
||||||
|
deviceId(disco->DeviceId),
|
||||||
|
expires(disco->Expires) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptor for one device having a Content Directory
|
||||||
|
* service found on the network.
|
||||||
|
*/
|
||||||
|
class ContentDirectoryDescriptor {
|
||||||
|
public:
|
||||||
|
ContentDirectoryDescriptor(const std::string &url,
|
||||||
|
const std::string &description,
|
||||||
|
time_t last, int exp)
|
||||||
|
:device(url, description), last_seen(last), expires(exp+20) {}
|
||||||
|
UPnPDevice device;
|
||||||
|
time_t last_seen;
|
||||||
|
int expires; // seconds valid
|
||||||
|
};
|
||||||
|
|
||||||
LibUPnP *const lib;
|
LibUPnP *const lib;
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
|
|
||||||
|
Mutex mutex;
|
||||||
|
std::map<std::string, ContentDirectoryDescriptor> directories;
|
||||||
|
WorkQueue<DiscoveredTask *> discoveredQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The UPnP device search timeout, which should actually be
|
* The UPnP device search timeout, which should actually be
|
||||||
* called delay because it's the base of a random delay that
|
* called delay because it's the base of a random delay that
|
||||||
|
@ -85,6 +128,18 @@ private:
|
||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
void expireDevices();
|
void expireDevices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worker routine for the discovery queue. Get messages about
|
||||||
|
* devices appearing and disappearing, and update the
|
||||||
|
* directory pool accordingly.
|
||||||
|
*/
|
||||||
|
static void *discoExplorer(void *);
|
||||||
|
void discoExplorer();
|
||||||
|
|
||||||
|
int OnAlive(Upnp_Discovery *disco);
|
||||||
|
int OnByeBye(Upnp_Discovery *disco);
|
||||||
|
int cluCallBack(Upnp_EventType et, void *evp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
Loading…
Reference in New Issue