db/upnp/Discovery: move callbacks and data structures into class

Eliminate global variables.
This commit is contained in:
Max Kellermann 2014-01-16 12:50:59 +01:00
parent aa64a5328e
commit e2812f722d
3 changed files with 80 additions and 72 deletions

View File

@ -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++) {

View File

@ -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);
}; };

View File

@ -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>