From f5015bcfbadda1ddc0e4870fd810523c58b84c19 Mon Sep 17 00:00:00 2001 From: Rolf Ahrenberg Date: Mon, 17 Nov 2014 00:23:20 +0200 Subject: [PATCH] Refactored device discovery. --- Makefile | 4 +- discover.c | 156 +++++++++++++++++++---------------------------------- discover.h | 14 +++-- msearch.c | 94 ++++++++++++++++++++++++++++++++ msearch.h | 37 +++++++++++++ satip.c | 4 +- 6 files changed, 197 insertions(+), 112 deletions(-) create mode 100644 msearch.c create mode 100644 msearch.h diff --git a/Makefile b/Makefile index 1287ca1..9784547 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/discover.c b/discover.c index 795fa4b..4433243 100644 --- a/discover.c +++ b/discover.c @@ -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(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(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); } } diff --git a/discover.h b/discover.h index d6d00bc..6cb04a9 100644 --- a/discover.h +++ b/discover.h @@ -13,6 +13,7 @@ #include #include +#include "msearch.h" #include "server.h" #include "socket.h" @@ -37,29 +38,25 @@ class cSatipDiscoverServers : public cList { 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); diff --git a/msearch.c b/msearch.c new file mode 100644 index 0000000..dee74c6 --- /dev/null +++ b/msearch.c @@ -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(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(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); + } + } + } +} diff --git a/msearch.h b/msearch.h new file mode 100644 index 0000000..33e549c --- /dev/null +++ b/msearch.h @@ -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_ */ diff --git a/satip.c b/satip.c index 6b1255d..c232d1c 100644 --- a/satip.c +++ b/satip.c @@ -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(); }