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 "Discovery.hxx"
#include "Device.hxx"
#include "Domain.hxx"
#include "ContentDirectoryService.hxx"
#include "WorkQueue.hxx"
#include "upnpplib.hxx"
#include "thread/Mutex.hxx"
#include <upnp/upnp.h>
#include <upnp/upnptools.h>
#include <string.h>
#include <map>
// The service type string we are looking for.
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;
}
/**
* 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) {}
};
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 *)
inline void
UPnPDeviceDirectory::discoExplorer()
{
auto &mutex = contentDirectories.m_mutex;
auto &directories = contentDirectories.m_directories;
for (;;) {
DiscoveredTask *tsk = 0;
if (!discoveredQueue.take(tsk)) {
discoveredQueue.workerExit();
return (void*)1;
return;
}
const ScopeLock protect(mutex);
@ -156,8 +100,16 @@ discoExplorer(void *)
}
}
static int
OnAlive(Upnp_Discovery *disco)
void *
UPnPDeviceDirectory::discoExplorer(void *ctx)
{
UPnPDeviceDirectory &directory = *(UPnPDeviceDirectory *)ctx;
directory.discoExplorer();
return (void*)1;
}
inline int
UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
{
if (isMSDevice(disco->DeviceType) ||
isCDService(disco->ServiceType)) {
@ -169,8 +121,8 @@ OnAlive(Upnp_Discovery *disco)
return UPNP_E_SUCCESS;
}
static int
OnByeBye(Upnp_Discovery *disco)
inline int
UPnPDeviceDirectory::OnByeBye(Upnp_Discovery *disco)
{
if (isMSDevice(disco->DeviceType) ||
@ -187,8 +139,8 @@ OnByeBye(Upnp_Discovery *disco)
// thread context.
// Example: ContentDirectories appearing and disappearing from the network
// We queue a task for our worker thread(s)
static int
cluCallBack(Upnp_EventType et, void *evp)
inline int
UPnPDeviceDirectory::cluCallBack(Upnp_EventType et, void *evp)
{
switch (et) {
case UPNP_DISCOVERY_SEARCH_RESULT:
@ -215,8 +167,7 @@ cluCallBack(Upnp_EventType et, void *evp)
void
UPnPDeviceDirectory::expireDevices()
{
const ScopeLock protect(contentDirectories.m_mutex);
auto &directories = contentDirectories.m_directories;
const ScopeLock protect(mutex);
time_t now = time(0);
bool didsomething = false;
@ -235,14 +186,16 @@ UPnPDeviceDirectory::expireDevices()
}
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");
return;
}
lib->SetHandler([](Upnp_EventType type, void *event){
lib->SetHandler([this](Upnp_EventType type, void *event){
cluCallBack(type, event);
});
@ -288,8 +241,7 @@ UPnPDeviceDirectory::getDirServices(std::vector<ContentDirectoryService> &out)
// Has locking, do it before our own lock
expireDevices();
const ScopeLock protect(contentDirectories.m_mutex);
auto &directories = contentDirectories.m_directories;
const ScopeLock protect(mutex);
for (auto dit = directories.begin();
dit != directories.end(); dit++) {

View File

@ -20,9 +20,16 @@
#ifndef _UPNPPDISC_H_X_INCLUDED_
#define _UPNPPDISC_H_X_INCLUDED_
#include "Device.hxx"
#include "WorkQueue.hxx"
#include "thread/Mutex.hxx"
#include "util/Error.hxx"
#include <upnp/upnp.h>
#include <map>
#include <vector>
#include <string>
#include <time.h>
@ -36,10 +43,46 @@ class ContentDirectoryService;
* for now, but this could be made more general, by removing the filtering.
*/
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;
Error error;
Mutex mutex;
std::map<std::string, ContentDirectoryDescriptor> directories;
WorkQueue<DiscoveredTask *> discoveredQueue;
/**
* The UPnP device search timeout, which should actually be
* called delay because it's the base of a random delay that
@ -85,6 +128,18 @@ private:
* directory.
*/
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/Cond.hxx"
#include <assert.h>
#include <pthread.h>
#include <string>