vdr-plugin-satip/discover.c

336 lines
9.4 KiB
C
Raw Normal View History

2014-03-08 12:07:47 +01:00
/*
* discover.c: SAT>IP plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
*/
#include <string.h>
#ifdef USE_TINYXML
#include <tinyxml.h>
#else
#include <pugixml.hpp>
#endif
2014-03-08 12:07:47 +01:00
#include "common.h"
#include "config.h"
2014-12-05 22:14:40 +01:00
#include "log.h"
2014-03-08 12:07:47 +01:00
#include "socket.h"
#include "discover.h"
cSatipDiscover *cSatipDiscover::instanceS = NULL;
cSatipDiscover *cSatipDiscover::GetInstance(void)
{
if (!instanceS)
instanceS = new cSatipDiscover();
return instanceS;
}
bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP)
2014-03-08 12:07:47 +01:00
{
2014-12-06 16:02:45 +01:00
debug1("%s", __PRETTY_FUNCTION__);
if (instanceS) {
if (serversP) {
for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s))
instanceS->AddServer(s->IpAddress(), s->Model(), s->Description());
}
else
instanceS->Activate();
}
2014-03-08 12:07:47 +01:00
return true;
}
void cSatipDiscover::Destroy(void)
{
2014-12-06 16:02:45 +01:00
debug1("%s", __PRETTY_FUNCTION__);
if (instanceS)
instanceS->Deactivate();
2014-03-08 12:07:47 +01:00
}
size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
2014-03-08 12:07:47 +01:00
{
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
2014-03-08 12:07:47 +01:00
if (obj) {
CURLcode res = CURLE_OK;
const char *desc = NULL, *model = NULL, *addr = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
char *xml = MALLOC(char, len + 1);
memcpy(xml, ptrP, len);
*(xml + len + 1) = 0;
doc.Parse((const char *)xml);
TiXmlHandle docHandle(&doc);
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
if (descElement)
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
if (modelElement)
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
#else
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_buffer(ptrP, len);
if (result) {
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
if (descNode)
desc = descNode.text().as_string("MyBrokenHardware");
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
if (modelNode)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
2014-03-08 12:07:47 +01:00
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
obj->AddServer(addr, model, desc);
2014-03-08 12:07:47 +01:00
}
return len;
}
2014-11-09 19:32:08 +01:00
int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
{
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(userPtrP);
if (obj) {
switch (typeP) {
case CURLINFO_TEXT:
2014-12-06 16:02:45 +01:00
debug2("%s HTTP INFO %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
2014-11-09 19:32:08 +01:00
break;
case CURLINFO_HEADER_IN:
2014-12-06 16:02:45 +01:00
debug2("%s HTTP HEAD <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
2014-11-09 19:32:08 +01:00
break;
case CURLINFO_HEADER_OUT:
2014-12-06 16:02:45 +01:00
debug2("%s HTTP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
2014-11-09 19:32:08 +01:00
break;
case CURLINFO_DATA_IN:
2014-12-06 16:02:45 +01:00
debug2("%s HTTP DATA <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
2014-11-09 19:32:08 +01:00
break;
case CURLINFO_DATA_OUT:
2014-12-06 16:02:45 +01:00
debug2("%s HTTP DATA >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
2014-11-09 19:32:08 +01:00
break;
default:
break;
}
}
return 0;
}
2014-03-08 12:07:47 +01:00
cSatipDiscover::cSatipDiscover()
: cThread("SATIP discover"),
2014-03-08 12:07:47 +01:00
mutexM(),
2014-11-29 14:37:21 +01:00
msearchM(*this),
2014-11-16 23:23:20 +01:00
probeUrlListM(),
2014-03-08 12:07:47 +01:00
handleM(curl_easy_init()),
sleepM(),
probeIntervalM(0),
2014-11-17 21:33:38 +01:00
serversM()
2014-03-08 12:07:47 +01:00
{
2014-12-06 16:02:45 +01:00
debug1("%s", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
}
cSatipDiscover::~cSatipDiscover()
{
2014-12-06 16:02:45 +01:00
debug1("%s", __PRETTY_FUNCTION__);
Deactivate();
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
// Free allocated memory
if (handleM)
curl_easy_cleanup(handleM);
handleM = NULL;
2014-11-16 23:23:20 +01:00
probeUrlListM.Clear();
2014-03-08 12:07:47 +01:00
}
void cSatipDiscover::Activate(void)
{
// Start the thread
Start();
}
void cSatipDiscover::Deactivate(void)
{
2014-12-06 16:02:45 +01:00
debug1("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
sleepM.Signal();
if (Running())
Cancel(3);
}
2014-03-08 12:07:47 +01:00
void cSatipDiscover::Action(void)
{
2014-12-06 16:02:45 +01:00
debug1("%s Entering", __PRETTY_FUNCTION__);
2014-11-16 23:23:20 +01:00
probeIntervalM.Set(eProbeIntervalMs);
msearchM.Probe();
2014-03-08 12:07:47 +01:00
// Do the thread loop
while (Running()) {
2014-11-16 23:23:20 +01:00
cStringList tmp;
2014-03-08 12:07:47 +01:00
if (probeIntervalM.TimedOut()) {
probeIntervalM.Set(eProbeIntervalMs);
2014-11-16 23:23:20 +01:00
msearchM.Probe();
mutexM.Lock();
2014-11-17 21:33:38 +01:00
serversM.Cleanup(eProbeIntervalMs * 2);
2014-11-16 23:23:20 +01:00
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();
2014-03-08 12:07:47 +01:00
}
// to avoid busy loop and reduce cpu load
2014-11-16 23:23:20 +01:00
sleepM.Wait(eSleepTimeoutMs);
2014-03-08 12:07:47 +01:00
}
2014-12-06 16:02:45 +01:00
debug1("%s Exiting", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
}
2014-11-16 23:23:20 +01:00
void cSatipDiscover::Fetch(const char *urlP)
2014-03-08 12:07:47 +01:00
{
2014-12-07 16:27:53 +01:00
debug1("%s (%s)", __PRETTY_FUNCTION__, urlP);
2014-11-16 23:23:20 +01:00
if (handleM && !isempty(urlP)) {
long rc = 0;
CURLcode res = CURLE_OK;
2014-11-16 23:23:20 +01:00
// Verbose output
2014-12-07 22:14:02 +01:00
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);
2014-11-16 23:23:20 +01:00
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
2014-03-08 12:07:47 +01:00
2014-11-16 23:23:20 +01:00
// No progress meter and no signaling
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
2014-03-08 12:07:47 +01:00
2014-11-16 23:23:20 +01:00
// Set timeouts
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
2014-03-08 12:07:47 +01:00
2014-11-16 23:23:20 +01:00
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
2014-03-08 12:07:47 +01:00
2014-11-16 23:23:20 +01:00
// Set URL
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP);
2014-03-08 12:07:47 +01:00
2014-11-16 23:23:20 +01:00
// 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);
2014-03-08 12:07:47 +01:00
}
}
void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
2014-03-08 12:07:47 +01:00
{
2014-12-07 16:27:53 +01:00
debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
if (SatipConfig.GetUseSingleModelServers()) {
int n = 0;
char *s, *p = strdup(modelP);
char *r = strtok_r(p, ",", &s);
while (r) {
r = skipspace(r);
cString desc = cString::sprintf("%s #%d", descP, n++);
cSatipServer *tmp = new cSatipServer(addrP, r, desc);
if (!serversM.Update(tmp)) {
2015-01-15 22:37:36 +01:00
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
serversM.Add(tmp);
}
else
DELETENULL(tmp);
r = strtok_r(NULL, ",\n", &s);
}
FREE_POINTER(p);
}
else {
cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
if (!serversM.Update(tmp)) {
2015-01-15 22:37:36 +01:00
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
serversM.Add(tmp);
}
else
DELETENULL(tmp);
2014-03-08 12:07:47 +01:00
}
}
int cSatipDiscover::GetServerCount(void)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.Count();
}
cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP)
2014-03-08 12:07:47 +01:00
{
debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.Find(sourceP, transponderP, systemP);
2014-03-08 12:07:47 +01:00
}
cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
2014-03-08 12:07:47 +01:00
{
debug16("%s", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.Find(serverP);
2014-03-08 12:07:47 +01:00
}
cSatipServers *cSatipDiscover::GetServers(void)
{
debug16("%s", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return &serversM;
2014-03-08 12:07:47 +01:00
}
cString cSatipDiscover::GetServerString(cSatipServer *serverP)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.GetString(serverP);
}
2014-03-08 12:07:47 +01:00
cString cSatipDiscover::GetServerList(void)
{
debug16("%s", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.List();
}
void cSatipDiscover::SetTransponder(cSatipServer *serverP, int transponderP)
{
debug16("%s (, %d)", __PRETTY_FUNCTION__, transponderP);
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
serversM.SetTransponder(serverP, transponderP);
}
void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP)
{
debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
serversM.Use(serverP, onOffP);
2014-03-08 12:07:47 +01:00
}
int cSatipDiscover::NumProvidedSystems(void)
{
debug16("%s", __PRETTY_FUNCTION__);
2014-03-08 12:07:47 +01:00
cMutexLock MutexLock(&mutexM);
2014-11-17 21:33:38 +01:00
return serversM.NumProvidedSystems();
2014-03-08 12:07:47 +01:00
}
2014-11-29 14:37:21 +01:00
void cSatipDiscover::SetUrl(const char *urlP)
{
debug16("%s (%s)", __PRETTY_FUNCTION__, urlP);
2014-11-29 14:37:21 +01:00
mutexM.Lock();
probeUrlListM.Insert(strdup(urlP));
mutexM.Unlock();
sleepM.Signal();
}