Refactored device discovery.

This commit is contained in:
Rolf Ahrenberg 2014-11-17 00:23:20 +02:00
parent 443dd9706a
commit f5015bcfba
6 changed files with 197 additions and 112 deletions

View File

@ -88,8 +88,8 @@ all-redirect: all
### The object files (add further files here):
OBJS = $(PLUGIN).o common.o config.o device.o discover.o param.o poller.o \
rtp.o rtcp.o rtsp.o sectionfilter.o server.o setup.o socket.o \
OBJS = $(PLUGIN).o common.o config.o device.o discover.o msearch.o param.o \
poller.o rtp.o rtcp.o rtsp.o sectionfilter.o server.o setup.o socket.o \
statistics.o tuner.o
### The main target:

View File

@ -18,13 +18,6 @@
cSatipDiscover *cSatipDiscover::instanceS = NULL;
const char *cSatipDiscover::bcastAddressS = "239.255.255.250";
const char *cSatipDiscover::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
"HOST: 239.255.255.250:1900\r\n" \
"MAN: \"ssdp:discover\"\r\n" \
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
"MX: 2\r\n\r\n";
cSatipDiscover *cSatipDiscover::GetInstance(void)
{
if (!instanceS)
@ -126,8 +119,9 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data
cSatipDiscover::cSatipDiscover()
: cThread("SAT>IP discover"),
mutexM(),
msearchM(),
probeUrlListM(),
handleM(curl_easy_init()),
socketM(new cSatipSocket()),
sleepM(),
probeIntervalM(0),
serversM(new cSatipServers())
@ -141,11 +135,11 @@ cSatipDiscover::~cSatipDiscover()
Deactivate();
cMutexLock MutexLock(&mutexM);
// Free allocated memory
DELETENULL(socketM);
DELETENULL(serversM);
if (handleM)
curl_easy_cleanup(handleM);
handleM = NULL;
probeUrlListM.Clear();
}
void cSatipDiscover::Activate(void)
@ -166,119 +160,81 @@ void cSatipDiscover::Deactivate(void)
void cSatipDiscover::Action(void)
{
debug("cSatipDiscover::%s(): entering", __FUNCTION__);
probeIntervalM.Set(eProbeIntervalMs);
msearchM.Probe();
// Do the thread loop
while (Running()) {
cStringList tmp;
if (probeIntervalM.TimedOut()) {
probeIntervalM.Set(eProbeIntervalMs);
Probe();
Janitor();
msearchM.Probe();
mutexM.Lock();
if (serversM)
serversM->Cleanup(eProbeIntervalMs * 2);
mutexM.Unlock();
}
mutexM.Lock();
if (probeUrlListM.Size()) {
for (int i = 0; i < probeUrlListM.Size(); ++i)
tmp.Insert(strdup(probeUrlListM.At(i)));
probeUrlListM.Clear();
}
mutexM.Unlock();
if (tmp.Size()) {
for (int i = 0; i < tmp.Size(); ++i)
Fetch(tmp.At(i));
tmp.Clear();
}
// to avoid busy loop and reduce cpu load
sleepM.Wait(10);
sleepM.Wait(eSleepTimeoutMs);
}
debug("cSatipDiscover::%s(): exiting", __FUNCTION__);
}
void cSatipDiscover::Janitor(void)
void cSatipDiscover::Probe(const char *urlP)
{
debug("cSatipDiscover::%s()", __FUNCTION__);
debug("cSatipDiscover::%s(%s)", __FUNCTION__, urlP);
cMutexLock MutexLock(&mutexM);
if (serversM)
serversM->Cleanup(eProbeIntervalMs * 2);
probeUrlListM.Insert(strdup(urlP));
sleepM.Signal();
}
void cSatipDiscover::Probe(void)
void cSatipDiscover::Fetch(const char *urlP)
{
debug("cSatipDiscover::%s()", __FUNCTION__);
if (socketM && socketM->Open(eDiscoveryPort)) {
cTimeMs timeout(eProbeTimeoutMs);
socketM->Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
while (Running() && !timeout.TimedOut()) {
Read();
// to avoid busy loop and reduce cpu load
sleepM.Wait(100);
}
socketM->Close();
}
}
void cSatipDiscover::Read(void)
{
//debug("cSatipDiscover::%s()", __FUNCTION__);
if (socketM) {
unsigned char *buf = MALLOC(unsigned char, eProbeBufferSize + 1);
if (buf) {
memset(buf, 0, eProbeBufferSize + 1);
int len = socketM->Read(buf, eProbeBufferSize);
if (len > 0) {
//debug("cSatipDiscover::%s(): len=%d", __FUNCTION__, len);
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(buf), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
//debug("cSatipDiscover::%s(): %s", __FUNCTION__, r);
// Check the status code
// HTTP/1.1 200 OK
if (!status && startswith(r, "HTTP/1.1 200 OK")) {
status = true;
}
if (status) {
// Check the location data
// LOCATION: http://192.168.0.115:8888/octonet.xml
if (startswith(r, "LOCATION:")) {
location = compactspace(r + 9);
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
}
// Check the source type
// ST: urn:ses-com:device:SatIPServer:1
else if (startswith(r, "ST:")) {
char *st = compactspace(r + 3);
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
valid = true;
debug("cSatipDiscover::%s(): st='%s'", __FUNCTION__, st);
}
// Check whether all the required data is found
if (valid && !isempty(location))
break;
}
r = strtok_r(NULL, "\r\n", &s);
}
if (handleM && valid && !isempty(location)) {
long rc = 0;
CURLcode res = CURLE_OK;
debug("cSatipDiscover::%s(%s)", __FUNCTION__, urlP);
if (handleM && !isempty(urlP)) {
long rc = 0;
CURLcode res = CURLE_OK;
#ifdef DEBUG
// Verbose output
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
// Verbose output
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
#endif
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
// No progress meter and no signaling
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
// No progress meter and no signaling
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
// Set timeouts
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
// Set timeouts
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
// Set URL
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, location);
// Set URL
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP);
// Fetch the data
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
if (rc != 200)
error("Discovery detected invalid status code: %ld", rc);
}
}
free(buf);
}
// Fetch the data
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
if (rc != 200)
error("Discovery detected invalid status code: %ld", rc);
}
}

View File

@ -13,6 +13,7 @@
#include <vdr/thread.h>
#include <vdr/tools.h>
#include "msearch.h"
#include "server.h"
#include "socket.h"
@ -37,29 +38,25 @@ class cSatipDiscoverServers : public cList<cSatipDiscoverServer> {
class cSatipDiscover : public cThread {
private:
enum {
eSleepTimeoutMs = 500, // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
eDiscoveryPort = 1900,
eProbeBufferSize = 1024, // in bytes
eProbeTimeoutMs = 2000, // in milliseconds
eProbeIntervalMs = 60000 // in milliseconds
};
static cSatipDiscover *instanceS;
static const char *bcastAddressS;
static const char *bcastMessageS;
static size_t WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
cMutex mutexM;
cSatipMsearch msearchM;
cStringList probeUrlListM;
CURL *handleM;
cSatipSocket *socketM;
cCondWait sleepM;
cTimeMs probeIntervalM;
cSatipServers *serversM;
void Activate(void);
void Deactivate(void);
void Janitor(void);
void Probe(void);
void Read(void);
void AddServer(const char *addrP, const char *modelP, const char *descP);
void Fetch(const char *urlP);
// constructor
cSatipDiscover();
// to prevent copy constructor and assignment
@ -74,6 +71,7 @@ public:
static bool Initialize(cSatipDiscoverServers *serversP);
static void Destroy(void);
virtual ~cSatipDiscover();
void Probe(const char *urlP);
void TriggerScan(void) { probeIntervalM.Set(0); }
int GetServerCount(void);
cSatipServer *GetServer(int sourceP, int transponderP = 0, int systemP = -1);

94
msearch.c Normal file
View File

@ -0,0 +1,94 @@
/*
* msearch.c: SAT>IP plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#include "common.h"
#include "discover.h"
#include "poller.h"
#include "msearch.h"
const char *cSatipMsearch::bcastAddressS = "239.255.255.250";
const char *cSatipMsearch::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
"HOST: 239.255.255.250:1900\r\n" \
"MAN: \"ssdp:discover\"\r\n" \
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
"MX: 2\r\n\r\n";
cSatipMsearch::cSatipMsearch(void)
: bufferLenM(eProbeBufferSize),
bufferM(MALLOC(unsigned char, bufferLenM)),
registeredM(false)
{
if (bufferM)
memset(bufferM, 0, bufferLenM);
else
error("Cannot create Msearch buffer!");
if (!Open(eDiscoveryPort))
error("Cannot open Msearch port!");
}
cSatipMsearch::~cSatipMsearch()
{
}
void cSatipMsearch::Probe(void)
{
debug("cSatipMsearch::%s()", __FUNCTION__);
if (!registeredM) {
cSatipPoller::GetInstance()->Register(*this);
registeredM = true;
}
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
}
int cSatipMsearch::GetFd(void)
{
return Fd();
}
void cSatipMsearch::Process(int fdP)
{
//debug("cSatipMsearch::%s()", __FUNCTION__);
if (bufferM) {
int length = Read(bufferM, bufferLenM);
if (length > 0) {
bufferM[min(length, int(bufferLenM - 1))] = 0;
//debug("cSatipMsearch::%s(): len=%d buf=%s", __FUNCTION__, length, bufferM);
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
//debug("cSatipMsearch::%s(): %s", __FUNCTION__, r);
// Check the status code
// HTTP/1.1 200 OK
if (!status && startswith(r, "HTTP/1.1 200 OK"))
status = true;
if (status) {
// Check the location data
// LOCATION: http://192.168.0.115:8888/octonet.xml
if (startswith(r, "LOCATION:")) {
location = compactspace(r + 9);
debug("cSatipMsearch::%s(): location='%s'", __FUNCTION__, location);
}
// Check the source type
// ST: urn:ses-com:device:SatIPServer:1
else if (startswith(r, "ST:")) {
char *st = compactspace(r + 3);
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
valid = true;
debug("cSatipMsearch::%s(): st='%s'", __FUNCTION__, st);
}
// Check whether all the required data is found
if (valid && !isempty(location)) {
cSatipDiscover::GetInstance()->Probe(location);
break;
}
}
r = strtok_r(NULL, "\r\n", &s);
}
}
}
}

37
msearch.h Normal file
View File

@ -0,0 +1,37 @@
/*
* msearch.h: SAT>IP plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#ifndef __SATIP_MSEARCH_H_
#define __SATIP_MSEARCH_H_
#include "socket.h"
#include "pollerif.h"
class cSatipMsearch : public cSatipSocket, public cSatipPollerIf {
private:
enum {
eProbeBufferSize = 1024, // in bytes
eDiscoveryPort = 1900,
};
static const char *bcastAddressS;
static const char *bcastMessageS;
unsigned int bufferLenM;
unsigned char *bufferM;
bool registeredM;
public:
cSatipMsearch(void);
virtual ~cSatipMsearch();
void Probe(void);
// for internal poller interface
public:
virtual int GetFd(void);
virtual void Process(int fdP);
};
#endif /* __SATIP_MSEARCH_H_ */

View File

@ -117,8 +117,8 @@ bool cPluginSatip::Initialize(void)
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
error("Unable to initialize CURL");
SatipConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
cSatipDiscover::GetInstance()->Initialize(serversM);
cSatipPoller::GetInstance()->Initialize();
cSatipDiscover::GetInstance()->Initialize(serversM);
return cSatipDevice::Initialize(deviceCountM);
}
@ -142,8 +142,8 @@ void cPluginSatip::Stop(void)
debug("cPluginSatip::%s()", __FUNCTION__);
// Stop any background activities the plugin is performing.
cSatipDevice::Shutdown();
cSatipPoller::GetInstance()->Destroy();
cSatipDiscover::GetInstance()->Destroy();
cSatipPoller::GetInstance()->Destroy();
curl_global_cleanup();
}