[vdr-plugin-satip] 01/03: Imported Upstream version 2.2.0

Tobias Grimm tiber-guest at moszumanska.debian.org
Sun Mar 1 19:02:42 UTC 2015


This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a commit to branch master
in repository vdr-plugin-satip.

commit 0435b8b427738ebe3a60cc4c1d9e6ba18bcf824c
Author: etobi <git at e-tobi.net>
Date:   Sun Mar 1 19:59:53 2015 +0100

    Imported Upstream version 2.2.0
---
 HISTORY     |  12 +++
 README      |   8 +-
 device.c    |  14 +--
 discover.c  |  52 +++++++---
 discover.h  |  10 +-
 msearch.c   |   3 +-
 param.c     |   8 +-
 po/ca_ES.po |   6 +-
 po/de_DE.po |   6 +-
 po/es_ES.po |   6 +-
 po/fi_FI.po |   6 +-
 rtcp.c      |   4 +-
 rtp.c       |   5 +-
 satip.c     |   8 +-
 server.c    | 334 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 server.h    | 113 ++++++++++++--------
 setup.c     |   2 +-
 socket.c    |  15 +--
 tuner.c     |  48 +++++----
 tuner.h     |  60 ++++++-----
 20 files changed, 482 insertions(+), 238 deletions(-)

diff --git a/HISTORY b/HISTORY
index 0a1a70b..6ea4717 100644
--- a/HISTORY
+++ b/HISTORY
@@ -108,3 +108,15 @@ VDR Plugin 'satip' Revision History
 - Updated Spanish and Catalan translations (Thanks to
   Gabriel Bonich).
 - Updated German translations (Thanks to Frank Neumann).
+
+
+===================================
+VDR Plugin 'satip' Revision History
+===================================
+
+2015-02-19: Version 2.2.0
+
+- Updated for vdr-2.2.0.
+- Fixed memory deallocation errors.
+- Cleaned up all scan-build warnings.
+- Refactored the frontend handling.
diff --git a/README b/README
index 07139d9..7a44ccf 100644
--- a/README
+++ b/README
@@ -26,10 +26,6 @@ Requirements:
 - Glibc >= 2.12 - the GNU C library (recvmmsg)
   http://www.gnu.org/software/libc/
 
-- VDR >= 2.1.4 for scrambled channels
-
-- VDR >= 2.1.7 for external CI
-
 Description:
 
 This plugin integrates SAT>IP network devices seamlessly into VDR.
@@ -136,8 +132,8 @@ Notes:
   your setup doesn't have firewalled the UDP port 1900.
 
 - Stream decryption requires a separate CAM plugin that works without
-  direct access to any DVB card devices. The integrated CAM slot in
-  Octopus Net devices isn't supported.
+  direct access to any DVB card devices. Also the integrated CAM slots
+  in Octopus Net devices are supported.
 
 - Tracing can be set on/off dynamically via command-line switch or
   SVDRP command.
diff --git a/device.c b/device.c
index cfaee19..6eb25cf 100644
--- a/device.c
+++ b/device.c
@@ -328,20 +328,19 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
         return false;
         }
      cString address;
-     cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), channelP->Transponder(), dtp.System());
+     cSatipServer *server = cSatipDiscover::GetInstance()->AssignServer(deviceIndexM, channelP->Source(), channelP->Transponder(), dtp.System());
      if (!server) {
         debug9("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
         return false;
         }
-     cSatipDiscover::GetInstance()->SetTransponder(server, channelP->Transponder());
-     if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) {
+     if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) {
         channelM = *channelP;
         deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
         return true;
         }
      }
   else if (pTunerM) {
-     pTunerM->SetSource(NULL, NULL, deviceIndexM);
+     pTunerM->SetSource(NULL, 0, NULL, deviceIndexM);
      return true;
      }
   return false;
@@ -434,10 +433,7 @@ int cSatipDevice::GetId(void)
 
 int cSatipDevice::GetPmtPid(void)
 {
-  int pid = 0;
-#if defined(APIVERSNUM) && APIVERSNUM >= 20107
-  pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
-#endif
+  int pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
   debug11("%s pmtpid=%d source=%c transponder=%d sid=%d name=%s [device %u]", __PRETTY_FUNCTION__, pid, cSource::ToChar(channelM.Source()), channelM.Transponder(), channelM.Sid(), channelM.Name(), deviceIndexM);
   return pid;
 }
@@ -506,7 +502,6 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP)
 {
   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
   if (tsBufferM) {
-#if defined(APIVERSNUM) && APIVERSNUM >= 20104
      if (cCamSlot *cs = CamSlot()) {
         if (cs->WantsTsData()) {
            int available;
@@ -518,7 +513,6 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP)
            return true;
            }
         }
-#endif
      dataP = GetData();
      return true;
      }
diff --git a/discover.c b/discover.c
index 91735bd..2a77325 100644
--- a/discover.c
+++ b/discover.c
@@ -233,7 +233,7 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char
 {
   debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
   cMutexLock MutexLock(&mutexM);
-  if (SatipConfig.GetUseSingleModelServers()) {
+  if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) {
      int n = 0;
      char *s, *p = strdup(modelP);
      char *r = strtok_r(p, ",", &s);
@@ -242,7 +242,7 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char
            cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++);
            cSatipServer *tmp = new cSatipServer(addrP, r, desc);
            if (!serversM.Update(tmp)) {
-              info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
+              info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
               serversM.Add(tmp);
               }
            else
@@ -254,7 +254,7 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char
   else {
      cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
      if (!serversM.Update(tmp)) {
-        info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
+        info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
         serversM.Add(tmp);
         }
      else
@@ -269,11 +269,18 @@ int cSatipDiscover::GetServerCount(void)
   return serversM.Count();
 }
 
-cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP)
+cSatipServer *cSatipDiscover::AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP)
 {
-  debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP);
+  debug16("%s (%d, %d, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, sourceP, transponderP, systemP);
   cMutexLock MutexLock(&mutexM);
-  return serversM.Find(sourceP, transponderP, systemP);
+  return serversM.Assign(deviceIdP, sourceP, transponderP, systemP);
+}
+
+cSatipServer *cSatipDiscover::GetServer(int sourceP)
+{
+  debug16("%s (%d)", __PRETTY_FUNCTION__, sourceP);
+  cMutexLock MutexLock(&mutexM);
+  return serversM.Find(sourceP);
 }
 
 cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
@@ -304,18 +311,39 @@ cString cSatipDiscover::GetServerList(void)
   return serversM.List();
 }
 
-void cSatipDiscover::SetTransponder(cSatipServer *serverP, int transponderP)
+void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
+{
+  debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
+  cMutexLock MutexLock(&mutexM);
+  serversM.Attach(serverP, deviceIdP, transponderP);
+}
+
+void cSatipDiscover::DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
+{
+  debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
+  cMutexLock MutexLock(&mutexM);
+  serversM.Detach(serverP, deviceIdP, transponderP);
+}
+
+bool cSatipDiscover::IsServerQuirk(cSatipServer *serverP, int quirkP)
 {
-  debug16("%s (, %d)", __PRETTY_FUNCTION__, transponderP);
+  debug16("%s (, %d)", __PRETTY_FUNCTION__, quirkP);
   cMutexLock MutexLock(&mutexM);
-  serversM.SetTransponder(serverP, transponderP);
+  return serversM.IsQuirk(serverP, quirkP);
 }
 
-void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP)
+bool cSatipDiscover::HasServerCI(cSatipServer *serverP)
 {
-  debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
+  debug16("%s", __PRETTY_FUNCTION__);
+  cMutexLock MutexLock(&mutexM);
+  return serversM.HasCI(serverP);
+}
+
+cString cSatipDiscover::GetServerAddress(cSatipServer *serverP)
+{
+  debug16("%s", __PRETTY_FUNCTION__);
   cMutexLock MutexLock(&mutexM);
-  serversM.Use(serverP, onOffP);
+  return serversM.GetAddress(serverP);
 }
 
 int cSatipDiscover::NumProvidedSystems(void)
diff --git a/discover.h b/discover.h
index 74e72b5..4984080 100644
--- a/discover.h
+++ b/discover.h
@@ -74,12 +74,16 @@ public:
   virtual ~cSatipDiscover();
   void TriggerScan(void) { probeIntervalM.Set(0); }
   int GetServerCount(void);
-  cSatipServer *GetServer(int sourceP, int transponderP = 0, int systemP = -1);
+  cSatipServer *AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP);
+  cSatipServer *GetServer(int sourceP);
   cSatipServer *GetServer(cSatipServer *serverP);
   cSatipServers *GetServers(void);
   cString GetServerString(cSatipServer *serverP);
-  void SetTransponder(cSatipServer *serverP, int transponderP);
-  void UseServer(cSatipServer *serverP, bool onOffP);
+  void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
+  void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
+  bool IsServerQuirk(cSatipServer *serverP, int quirkP);
+  bool HasServerCI(cSatipServer *serverP);
+  cString GetServerAddress(cSatipServer *serverP);
   cString GetServerList(void);
   int NumProvidedSystems(void);
 
diff --git a/msearch.c b/msearch.c
index 9f28d32..ab1fbad 100644
--- a/msearch.c
+++ b/msearch.c
@@ -35,6 +35,7 @@ cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP)
 
 cSatipMsearch::~cSatipMsearch()
 {
+  FREE_POINTER(bufferM);
 }
 
 void cSatipMsearch::Probe(void)
@@ -93,8 +94,6 @@ void cSatipMsearch::Process(void)
                  r = strtok_r(NULL, "\r\n", &s);
                  }
            }
-     if (errno != EAGAIN && errno != EWOULDBLOCK)
-        error("Error %d reading in %s", errno, *ToString());
      }
 }
 
diff --git a/param.c b/param.c
index d999a8f..03caa48 100644
--- a/param.c
+++ b/param.c
@@ -147,15 +147,9 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
      cDvbTransponderParameters dtp(channelP->Parameters());
      int DataSlice = 0;
      int C2TuningFrequencyType = 0;
-#if defined(APIVERSNUM) && APIVERSNUM < 20106
-     int Pilot = PILOT_AUTO;
-     int T2SystemId = 0;
-     int SisoMiso = 0;
-#else
      int Pilot = dtp.Pilot();
      int T2SystemId = dtp.T2SystemId();
      int SisoMiso = dtp.SisoMiso();
-#endif
      float freq = channelP->Frequency();
      char type = cSource::ToChar(channelP->Source());
      cSource *source = Sources.Get(channelP->Source());
@@ -192,7 +186,7 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesTerrestrial);
      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
      if ((channelP->Rid() % 100) > 0)
-                q += snprintf(q,       STBUFLEFT, "&fe=%d",           channelP->Rid() % 100);
+                snprintf(q,            STBUFLEFT, "&fe=%d",           channelP->Rid() % 100);
 #undef ST
      return buffer;
      }
diff --git a/po/ca_ES.po b/po/ca_ES.po
index 05c01a1..e9ef289 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: vdr-satip 1.0.2\n"
+"Project-Id-Version: vdr-satip 2.2.0\n"
 "Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-01-18 01:18+0200\n"
-"PO-Revision-Date: 2015-01-18 01:18+0200\n"
+"POT-Creation-Date: 2015-02-19 02:19+0200\n"
+"PO-Revision-Date: 2015-02-19 02:19+0200\n"
 "Last-Translator: Gabriel Bonich <gbonich at gmail.com>\n"
 "Language-Team: Catalan <vdr at linuxtv.org>\n"
 "Language: ca\n"
diff --git a/po/de_DE.po b/po/de_DE.po
index 0489acf..9cd77ec 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: vdr-satip 1.0.2\n"
+"Project-Id-Version: vdr-satip 2.2.0\n"
 "Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-01-18 01:18+0200\n"
-"PO-Revision-Date: 2015-01-18 01:18+0200\n"
+"POT-Creation-Date: 2015-02-19 02:19+0200\n"
+"PO-Revision-Date: 2015-02-19 02:19+0200\n"
 "Last-Translator: Frank Neumann <fnu at yavdr.org>\n"
 "Language-Team: German <vdr at linuxtv.org>\n"
 "Language: de\n"
diff --git a/po/es_ES.po b/po/es_ES.po
index 2dcf9eb..724f5fb 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: vdr-satip 1.0.2\n"
+"Project-Id-Version: vdr-satip 2.2.0\n"
 "Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-01-18 01:18+0200\n"
-"PO-Revision-Date: 2015-01-18 01:18+0200\n"
+"POT-Creation-Date: 2015-02-19 02:19+0200\n"
+"PO-Revision-Date: 2015-02-19 02:19+0200\n"
 "Last-Translator: Gabriel Bonich <gbonich at gmail.com>\n"
 "Language-Team: Spanish <vdr at linuxtv.org>\n"
 "Language: es\n"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index 3694cee..0b27822 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -5,10 +5,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: vdr-satip 1.0.2\n"
+"Project-Id-Version: vdr-satip 2.2.0\n"
 "Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-01-18 01:18+0200\n"
-"PO-Revision-Date: 2015-01-18 01:18+0200\n"
+"POT-Creation-Date: 2015-02-19 02:19+0200\n"
+"PO-Revision-Date: 2015-02-19 02:19+0200\n"
 "Last-Translator: Rolf Ahrenberg\n"
 "Language-Team: Finnish <vdr at linuxtv.org>\n"
 "Language: fi\n"
diff --git a/rtcp.c b/rtcp.c
index 4008633..f88c805 100644
--- a/rtcp.c
+++ b/rtcp.c
@@ -25,7 +25,7 @@ cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP)
 cSatipRtcp::~cSatipRtcp()
 {
   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
-  DELETE_POINTER(bufferM);
+  FREE_POINTER(bufferM);
 }
 
 int cSatipRtcp::GetFd(void)
@@ -89,8 +89,6 @@ void cSatipRtcp::Process(void)
            if (offset >= 0)
               tunerM.ProcessApplicationData(bufferM + offset, length);
            }
-     if (errno != EAGAIN && errno != EWOULDBLOCK)
-        error("Error %d reading in %s", errno, *ToString());
      }
 }
 
diff --git a/rtp.c b/rtp.c
index 3d033f9..0be033a 100644
--- a/rtp.c
+++ b/rtp.c
@@ -29,7 +29,7 @@ cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
 cSatipRtp::~cSatipRtp()
 {
   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
-  DELETE_POINTER(bufferM);
+  FREE_POINTER(bufferM);
 }
 
 int cSatipRtp::GetFd(void)
@@ -136,9 +136,6 @@ void cSatipRtp::Process(void)
            }
        } while (count >= eRtpPacketReadCount);
 
-     if (errno != EAGAIN && errno != EWOULDBLOCK)
-        error("Error %d reading in %s [device %d]", errno, *ToString(), tunerM.GetId());
-
      elapsed = processing.Elapsed();
      if (elapsed > 1)
         debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId());
diff --git a/satip.c b/satip.c
index 7ae3faa..b34da79 100644
--- a/satip.c
+++ b/satip.c
@@ -19,15 +19,15 @@
 #warning "CURL version >= 7.36.0 is recommended"
 #endif
 
-#if defined(APIVERSNUM) && APIVERSNUM < 20000
-#error "VDR-2.0.0 API version or greater is required!"
+#if defined(APIVERSNUM) && APIVERSNUM < 20200
+#error "VDR-2.2.0 API version or greater is required!"
 #endif
 
 #ifndef GITVERSION
 #define GITVERSION ""
 #endif
 
-       const char VERSION[]     = "1.0.2" GITVERSION;
+       const char VERSION[]     = "2.2.0" GITVERSION;
 static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
 
 class cPluginSatip : public cPlugin {
@@ -84,7 +84,7 @@ const char *cPluginSatip::CommandLineHelp(void)
   return "  -d <num>, --devices=<number>  set number of devices to be created\n"
          "  -t <mode>, --trace=<mode>     set the tracing mode\n"
          "  -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n"
-         "                                define hard-coded SAT>IP server(s)"
+         "                                define hard-coded SAT>IP server(s)\n"
          "  -S, --single                  set the single model server mode on\n"
          "  -n, --noquirks                disable all the server quirks\n";
 }
diff --git a/server.c b/server.c
index 65113ab..d3f6c67 100644
--- a/server.c
+++ b/server.c
@@ -12,73 +12,140 @@
 #include "log.h"
 #include "server.h"
 
+// --- cSatipFrontend ---------------------------------------------------------
+
+cSatipFrontend::cSatipFrontend(const int indexP, const char *descriptionP)
+: indexM(indexP),
+  transponderM(0),
+  deviceIdM(-1),
+  descriptionM(descriptionP)
+{
+}
+
+cSatipFrontend::~cSatipFrontend()
+{
+}
+
+// --- cSatipFrontends --------------------------------------------------------
+
+bool cSatipFrontends::Matches(int deviceIdP, int transponderP)
+{
+  for (cSatipFrontend *f = First(); f; f = Next(f)) {
+      if (f->Attached() && (f->DeviceId() == deviceIdP) && (f->Transponder() == transponderP))
+         return true;
+      }
+  return false;
+}
+
+bool cSatipFrontends::Assign(int deviceIdP, int transponderP)
+{
+  cSatipFrontend *tmp = NULL;
+  // Prefer any unused one
+  for (cSatipFrontend *f = First(); f; f = Next(f)) {
+      if (!f->Attached() || (f->DeviceId() == deviceIdP)) {
+         tmp = f;
+         break;
+         }
+      }
+  if (tmp) {
+     tmp->SetTransponder(transponderP);
+     return true;
+     }
+  return false;
+}
+
+bool cSatipFrontends::Attach(int deviceIdP, int transponderP)
+{
+  for (cSatipFrontend *f = First(); f; f = Next(f)) {
+      if (f->Transponder() == transponderP) {
+         f->Attach(deviceIdP);
+         debug9("%s (%d, %d) %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index());
+         return true;
+         }
+      }
+  return false;
+}
+
+bool cSatipFrontends::Detach(int deviceIdP, int transponderP)
+{
+  for (cSatipFrontend *f = First(); f; f = Next(f)) {
+      if (f->Transponder() == transponderP) {
+         f->Detach(deviceIdP);
+         debug9("%s (%d, %d) %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index());
+         return true;
+         }
+      }
+  return false;
+}
+
 // --- cSatipServer -----------------------------------------------------------
 
 cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP)
 : addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
   modelM((modelP && *modelP) ? modelP : "DVBS-1"),
   descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"),
-  modelTypeM(eSatipModelTypeNone),
+  quirksM(""),
   quirkM(eSatipQuirkNone),
-  useCountM(0),
-  transponderM(0),
+  hasCiM(false),
   createdM(time(NULL)),
   lastSeenM(0)
 {
-  memset(modelCountM, 0, sizeof(modelCountM));
   if (!SatipConfig.GetDisableServerQuirks()) {
-     debug3("%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM);
      // These devices contain a session id bug:
      // Inverto Airscreen Server IDL 400 ?
      // Elgato EyeTV Netstream 4Sat ?
      if (strstr(*descriptionM, "GSSBOX") ||             // Grundig Sat Systems GSS.box DSI 400
          strstr(*descriptionM, "DIGIBIT") ||            // Telestar Digibit R1
          strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
-        )
+        ) {
         quirkM |= eSatipQuirkSessionId;
+        quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
+        }
      // These devices contain a play (add/delpids) parameter bug:
-     if (strstr(*descriptionM, "fritzdvbc"))            // Fritz!WLAN Repeater DVB-C
+     if (strstr(*descriptionM, "fritzdvbc")             // Fritz!WLAN Repeater DVB-C
+        ) {
         quirkM |= eSatipQuirkPlayPids;
+        quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
+        }
      // These devices contain a frontend locking bug:
-     if (strstr(*descriptionM, "fritzdvbc"))            // Fritz!WLAN Repeater DVB-C
+     if (strstr(*descriptionM, "fritzdvbc")             // Fritz!WLAN Repeater DVB-C
+        ) {
         quirkM |= eSatipQuirkForceLock;
-     if (quirkM != eSatipQuirkNone)
-        info("Malfunctioning '%s' server detected! Please, fix the firmware.", *descriptionM);
+        quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
+        }
+     debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
      }
   // These devices support the X_PMT protocol extension
-  if (strstr(*descriptionM, "OctopusNet"))           // Digital Devices OctopusNet
-     quirkM |= eSatipQuirkUseXCI;
+  if (strstr(*descriptionM, "OctopusNet"))              // Digital Devices OctopusNet
+     hasCiM = true;
   char *s, *p = strdup(*modelM);
   char *r = strtok_r(p, ",", &s);
   while (r) {
-        if (strstr(r, "DVBS2-")) {
-           modelTypeM |= eSatipModelTypeDVBS2;
-           if (char *c = strstr(r, "-"))
-              modelCountM[eSatipModuleDVBS2] = atoi(++c);
+        char *c;
+        if (c = strstr(r, "DVBS2-")) {
+           int count = atoi(c + 6);
+           for (int i = 1; i <= count; ++i)
+               frontendsM[eSatipFrontendDVBS2].Add(new cSatipFrontend(i, "DVB-S2"));
            }
-        else if (strstr(r, "DVBT2-")) {
-           modelTypeM |= eSatipModelTypeDVBT2;
-           if (char *c = strstr(r, "-"))
-              modelCountM[eSatipModuleDVBT2] = atoi(++c);
-           modelTypeM |= eSatipModelTypeDVBT;
-           modelCountM[eSatipModuleDVBT] = modelCountM[eSatipModuleDVBT2];
+        else if (c = strstr(r, "DVBT-")) {
+           int count = atoi(c + 5);
+           for (int i = 1; i <= count; ++i)
+               frontendsM[eSatipFrontendDVBT].Add(new cSatipFrontend(i, "DVB-T"));
            }
-        else if (strstr(r, "DVBT-")) {
-           modelTypeM |= eSatipModelTypeDVBT;
-           if (char *c = strstr(r, "-"))
-              modelCountM[eSatipModuleDVBT] = atoi(++c);
+        else if (c = strstr(r, "DVBT2-")) {
+           int count = atoi(c + 6);
+           for (int i = 1; i <= count; ++i)
+               frontendsM[eSatipFrontendDVBT2].Add(new cSatipFrontend(i, "DVB-T2"));
            }
-        else if (strstr(r, "DVBC2-")) {
-           modelTypeM |= eSatipModelTypeDVBC2;
-           if (char *c = strstr(r, "-"))
-              modelCountM[eSatipModuleDVBC2] = atoi(++c);
-           modelTypeM |= eSatipModelTypeDVBC;
-           modelCountM[eSatipModuleDVBC] = modelCountM[eSatipModuleDVBC2];
+        else if (c = strstr(r, "DVBC-")) {
+           int count = atoi(c + 5);
+           for (int i = 1; i <= count; ++i)
+               frontendsM[eSatipFrontendDVBC].Add(new cSatipFrontend(i, "DVB-C"));
            }
-        else if (strstr(r, "DVBC-")) {
-           modelTypeM |= eSatipModelTypeDVBC;
-           if (char *c = strstr(r, "-"))
-              modelCountM[eSatipModuleDVBC] = atoi(++c);
+        else if (c = strstr(r, "DVBC2-")) {
+           int count = atoi(c + 6);
+           for (int i = 1; i <= count; ++i)
+               frontendsM[eSatipFrontendDVBC2].Add(new cSatipFrontend(i, "DVB-C2"));
            }
         r = strtok_r(NULL, ",", &s);
         }
@@ -101,12 +168,96 @@ int cSatipServer::Compare(const cListObject &listObjectP) const
   return result;
 }
 
-void cSatipServer::Use(bool onOffP)
+bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transponderP)
+{
+  bool result = false;
+  if (cSource::IsType(sourceP, 'S'))
+     result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP);
+  else if (cSource::IsType(sourceP, 'T')) {
+     if (systemP)
+        result = frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
+     else
+        result = frontendsM[eSatipFrontendDVBT].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
+     }
+  else if (cSource::IsType(sourceP, 'C')) {
+     if (systemP)
+        result = frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
+     else
+        result = frontendsM[eSatipFrontendDVBC].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
+     }
+  return result;
+}
+
+bool cSatipServer::Matches(int sourceP)
+{
+  if (cSource::IsType(sourceP, 'S'))
+     return GetModulesDVBS2();
+  else if (cSource::IsType(sourceP, 'T'))
+     return GetModulesDVBT() || GetModulesDVBT2();
+  else if (cSource::IsType(sourceP, 'C'))
+     return GetModulesDVBC() || GetModulesDVBC2();
+  return false;
+}
+
+bool cSatipServer::Matches(int deviceIdP, int sourceP, int systemP, int transponderP)
+{
+  bool result = false;
+  if (cSource::IsType(sourceP, 'S'))
+     result = frontendsM[eSatipFrontendDVBS2].Matches(deviceIdP, transponderP);
+  else if (cSource::IsType(sourceP, 'T')) {
+     if (systemP)
+        result = frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
+     else
+        result = frontendsM[eSatipFrontendDVBT].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
+     }
+  else if (cSource::IsType(sourceP, 'C')) {
+     if (systemP)
+        result = frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
+     else
+        result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
+     }
+  return result;
+}
+
+void cSatipServer::Attach(int deviceIdP, int transponderP)
+{
+  for (int i = 0; i < eSatipFrontendCount; ++i) {
+      if (frontendsM[i].Attach(deviceIdP, transponderP))
+         return;
+      }
+}
+
+void cSatipServer::Detach(int deviceIdP, int transponderP)
+{
+  for (int i = 0; i < eSatipFrontendCount; ++i) {
+      if (frontendsM[i].Detach(deviceIdP, transponderP))
+         return;
+      }
+}
+
+int cSatipServer::GetModulesDVBS2(void)
 {
-  if (onOffP)
-     ++useCountM;
-  else
-     --useCountM;
+  return frontendsM[eSatipFrontendDVBS2].Count();
+}
+
+int cSatipServer::GetModulesDVBT(void)
+{
+  return frontendsM[eSatipFrontendDVBT].Count();
+}
+
+int cSatipServer::GetModulesDVBT2(void)
+{
+  return frontendsM[eSatipFrontendDVBT2].Count();
+}
+
+int cSatipServer::GetModulesDVBC(void)
+{
+  return frontendsM[eSatipFrontendDVBC].Count();
+}
+
+int cSatipServer::GetModulesDVBC2(void)
+{
+  return frontendsM[eSatipFrontendDVBC2].Count();
 }
 
 // --- cSatipServers ----------------------------------------------------------
@@ -114,70 +265,87 @@ void cSatipServer::Use(bool onOffP)
 cSatipServer *cSatipServers::Find(cSatipServer *serverP)
 {
   for (cSatipServer *s = First(); s; s = Next(s)) {
-      if (s == serverP)
+      if (s->Compare(*serverP) == 0)
          return s;
       }
   return NULL;
 }
 
-cSatipServer *cSatipServers::Find(int sourceP, int transponderP, int systemP)
+cSatipServer *cSatipServers::Find(int sourceP)
+{
+  for (cSatipServer *s = First(); s; s = Next(s)) {
+      if (s->Matches(sourceP))
+         return s;
+      }
+  return NULL;
+}
+
+cSatipServer *cSatipServers::Assign(int deviceIdP, int sourceP, int transponderP, int systemP)
+{
+  for (cSatipServer *s = First(); s; s = Next(s)) {
+      if (s->Matches(deviceIdP, sourceP, systemP, transponderP))
+         return s;
+      }
+  for (cSatipServer *s = First(); s; s = Next(s)) {
+      if (s->Assign(deviceIdP, sourceP, systemP, transponderP))
+         return s;
+      }
+  return NULL;
+}
+
+cSatipServer *cSatipServers::Update(cSatipServer *serverP)
 {
-  cSatipServer *result = NULL;
-  int model = 0;
-  if (cSource::IsType(sourceP, 'S'))
-     model |= cSatipServer::eSatipModelTypeDVBS2;
-  else if (cSource::IsType(sourceP, 'T')) {
-     if (systemP < 0)
-        model |= cSatipServer::eSatipModelTypeDVBT2 | cSatipServer::eSatipModelTypeDVBT;
-     else
-        model |= systemP ? cSatipServer::eSatipModelTypeDVBT2 : cSatipServer::eSatipModelTypeDVBT;
-     }
-  else if (cSource::IsType(sourceP, 'C'))
-     model |= cSatipServer::eSatipModelTypeDVBC;
   for (cSatipServer *s = First(); s; s = Next(s)) {
-      if (s->Match(model) && s->Used() && (s->Transponder() == transponderP))
+      if (s->Compare(*serverP) == 0) {
+         s->Update();
          return s;
+         }
       }
+  return NULL;
+}
+
+void cSatipServers::Attach(cSatipServer *serverP, int deviceIdP, int transponderP)
+{
   for (cSatipServer *s = First(); s; s = Next(s)) {
-      if (s->Match(model)) {
-         result = s;
-         if (!s->Used()) {
-            break;
-            }
+      if (s == serverP) {
+         s->Attach(deviceIdP, transponderP);
+         break;
          }
       }
-  return result;
 }
 
-void cSatipServers::SetTransponder(cSatipServer *serverP, int transponderP)
+void cSatipServers::Detach(cSatipServer *serverP, int deviceIdP, int transponderP)
 {
   for (cSatipServer *s = First(); s; s = Next(s)) {
       if (s == serverP) {
-         s->SetTransponder(transponderP);
+         s->Detach(deviceIdP, transponderP);
          break;
          }
       }
 }
 
-cSatipServer *cSatipServers::Update(cSatipServer *serverP)
+bool cSatipServers::IsQuirk(cSatipServer *serverP, int quirkP)
 {
+  bool result = false;
   for (cSatipServer *s = First(); s; s = Next(s)) {
-      if (s->Compare(*serverP) == 0) {
-         s->Update();
-         return s;
+      if (s == serverP) {
+         result = s->Quirk(quirkP);
+         break;
          }
       }
-  return NULL;
+  return result;
 }
 
-void cSatipServers::Use(cSatipServer *serverP, bool onOffP)
+bool cSatipServers::HasCI(cSatipServer *serverP)
 {
+  bool result = false;
   for (cSatipServer *s = First(); s; s = Next(s)) {
       if (s == serverP) {
-         s->Use(onOffP);
+         result = s->HasCI();
          break;
          }
       }
+  return result;
 }
 
 void cSatipServers::Cleanup(uint64_t intervalMsP)
@@ -190,6 +358,18 @@ void cSatipServers::Cleanup(uint64_t intervalMsP)
       }
 }
 
+cString cSatipServers::GetAddress(cSatipServer *serverP)
+{
+  cString address = "";
+  for (cSatipServer *s = First(); s; s = Next(s)) {
+      if (s == serverP) {
+         address = s->Address();
+         break;
+         }
+      }
+  return address;
+}
+
 cString cSatipServers::GetString(cSatipServer *serverP)
 {
   cString list = "";
@@ -215,13 +395,15 @@ int cSatipServers::NumProvidedSystems(void)
   int count = 0;
   for (cSatipServer *s = First(); s; s = Next(s)) {
       // DVB-S2: qpsk, 8psk, 16apsk, 32apsk
-      count += s->Satellite() * 4;
-      // DVB-T2: qpsk, qam16, qam64, qam256
+      count += s->GetModulesDVBS2() * 4;
       // DVB-T: qpsk, qam16, qam64
-      count += s->Terrestrial2() ? s->Terrestrial2() * 4 : s->Terrestrial() * 3;
-      // DVB-C2: qam16, qam32, qam64, qam128, qam256
+      count += s->GetModulesDVBT() * 3;
+      // DVB-T2: qpsk, qam16, qam64, qam256
+      count += s->GetModulesDVBT2() * 4;
       // DVB-C: qam64, qam128, qam256
-      count += s->Cable2() ? s->Cable2() * 5 : s->Cable() * 3;
+      count += s->GetModulesDVBC() * 3;
+      // DVB-C2: qam16, qam32, qam64, qam128, qam256
+      count += s->GetModulesDVBC2() * 5;
       }
   return count;
 }
diff --git a/server.h b/server.h
index 2a21b73..45bb1df 100644
--- a/server.h
+++ b/server.h
@@ -8,26 +8,59 @@
 #ifndef __SATIP_SERVER_H
 #define __SATIP_SERVER_H
 
+class cSatipServer;
+
+// --- cSatipFrontend ---------------------------------------------------------
+
+class cSatipFrontend : public cListObject {
+private:
+  int indexM;
+  int transponderM;
+  int deviceIdM;
+  cString descriptionM;
+
+public:
+  cSatipFrontend(const int indexP, const char *descriptionP);
+  virtual ~cSatipFrontend();
+  void Attach(int deviceIdP) { deviceIdM = deviceIdP; }
+  void Detach(int deviceIdP) { if (deviceIdP == deviceIdM) deviceIdM = -1; }
+  cString Description(void) { return descriptionM; }
+  bool Attached(void) { return (deviceIdM >= 0); }
+  int Index(void) { return indexM; }
+  int Transponder(void) { return transponderM; }
+  int DeviceId(void) { return deviceIdM; }
+  void SetTransponder(int transponderP) { transponderM = transponderP; }
+};
+
+// --- cSatipFrontends --------------------------------------------------------
+
+class cSatipFrontends : public cList<cSatipFrontend> {
+public:
+  bool Matches(int deviceIdP, int transponderP);
+  bool Assign(int deviceIdP, int transponderP);
+  bool Attach(int deviceIdP, int transponderP);
+  bool Detach(int deviceIdP, int transponderP);
+};
+
 // --- cSatipServer -----------------------------------------------------------
 
 class cSatipServer : public cListObject {
 private:
-  enum eSatipModule {
-    eSatipModuleDVBS2 = 0,
-    eSatipModuleDVBT,
-    eSatipModuleDVBT2,
-    eSatipModuleDVBC,
-    eSatipModuleDVBC2,
-    eSatipModuleCount
+  enum eSatipFrontend {
+    eSatipFrontendDVBS2 = 0,
+    eSatipFrontendDVBT,
+    eSatipFrontendDVBT2,
+    eSatipFrontendDVBC,
+    eSatipFrontendDVBC2,
+    eSatipFrontendCount
   };
   cString addressM;
   cString modelM;
   cString descriptionM;
-  int modelCountM[eSatipModuleCount];
-  int modelTypeM;
+  cString quirksM;
+  cSatipFrontends frontendsM[eSatipFrontendCount];
   int quirkM;
-  int useCountM;
-  int transponderM;
+  bool hasCiM;
   time_t createdM;
   cTimeMs lastSeenM;
 
@@ -37,39 +70,31 @@ public:
     eSatipQuirkSessionId = 0x01,
     eSatipQuirkPlayPids  = 0x02,
     eSatipQuirkForceLock = 0x04,
-    eSatipQuirkUseXCI    = 0x08,
     eSatipQuirkMask      = 0x0F
   };
-  enum eSatipModelType {
-    eSatipModelTypeNone  = 0x00,
-    eSatipModelTypeDVBS2 = 0x01,
-    eSatipModelTypeDVBT  = 0x02,
-    eSatipModelTypeDVBT2 = 0x04,
-    eSatipModelTypeDVBC  = 0x08,
-    eSatipModelTypeDVBC2 = 0x10,
-    eSatipModelTypeMask  = 0xFF
-  };
   cSatipServer(const char *addressP, const char *modelP, const char *descriptionP);
   virtual ~cSatipServer();
   virtual int Compare(const cListObject &listObjectP) const;
-  void Use(bool onOffP);
-  void SetTransponder(const int transponderP) { transponderM = transponderP; }
-  int Transponder(void)     { return transponderM; }
-  bool Used(void)           { return !!useCountM; }
-  const char *Address()     { return *addressM; }
-  const char *Model(void)   { return *modelM; }
-  const char *Description() { return *descriptionM; }
-  bool Quirk(int quirkP)    { return ((quirkP & eSatipQuirkMask) & quirkM); }
-  int ModelType(void)       { return modelTypeM; }
-  bool Match(int modelP)    { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
-  int Cable()               { return Match(eSatipModelTypeDVBC)  ? modelCountM[eSatipModuleDVBC]  : 0; }
-  int Cable2()              { return Match(eSatipModelTypeDVBC2) ? modelCountM[eSatipModuleDVBC2] : 0; }
-  int Satellite()           { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; }
-  int Terrestrial()         { return Match(eSatipModelTypeDVBT)  ? modelCountM[eSatipModuleDVBT]  : 0; }
-  int Terrestrial2()        { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; }
-  void Update(void)         { lastSeenM.Set(); }
-  uint64_t LastSeen(void)   { return lastSeenM.Elapsed(); }
-  time_t Created(void)      { return createdM; }
+  bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP);
+  bool Matches(int sourceP);
+  bool Matches(int deviceIdP, int sourceP, int systemP, int transponderP);
+  void Attach(int deviceIdP, int transponderP);
+  void Detach(int deviceIdP, int transponderP);
+  int GetModulesDVBS2(void);
+  int GetModulesDVBT(void);
+  int GetModulesDVBT2(void);
+  int GetModulesDVBC(void);
+  int GetModulesDVBC2(void);
+  const char *Address(void)     { return *addressM; }
+  const char *Model(void)       { return *modelM; }
+  const char *Description(void) { return *descriptionM; }
+  const char *Quirks(void)      { return *quirksM; }
+  bool Quirk(int quirkP)        { return ((quirkP & eSatipQuirkMask) & quirkM); }
+  bool HasQuirk(void)           { return (quirkM != eSatipQuirkNone); }
+  bool HasCI(void)              { return hasCiM; }
+  void Update(void)             { lastSeenM.Set(); }
+  uint64_t LastSeen(void)       { return lastSeenM.Elapsed(); }
+  time_t Created(void)          { return createdM; }
 };
 
 // --- cSatipServers ----------------------------------------------------------
@@ -77,11 +102,15 @@ public:
 class cSatipServers : public cList<cSatipServer> {
 public:
   cSatipServer *Find(cSatipServer *serverP);
-  cSatipServer *Find(int sourceP, int transponderP, int systemP);
-  void SetTransponder(cSatipServer *serverP, int transponderP);
+  cSatipServer *Find(int sourceP);
+  cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP);
   cSatipServer *Update(cSatipServer *serverP);
-  void Use(cSatipServer *serverP, bool onOffP);
+  void Attach(cSatipServer *serverP, int deviceIdP, int transponderP);
+  void Detach(cSatipServer *serverP, int deviceIdP, int transponderP);
+  bool IsQuirk(cSatipServer *serverP, int quirkP);
+  bool HasCI(cSatipServer *serverP);
   void Cleanup(uint64_t intervalMsP = 0);
+  cString GetAddress(cSatipServer *serverP);
   cString GetString(cSatipServer *serverP);
   cString List(void);
   int NumProvidedSystems(void);
diff --git a/setup.c b/setup.c
index 9753f10..1319eb8 100644
--- a/setup.c
+++ b/setup.c
@@ -104,7 +104,7 @@ cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
   addressM(serverP ? serverP->Address() : "---"),
   modelM(serverP ? serverP->Model() : "---"),
   descriptionM(serverP ? serverP->Description() : "---"),
-  ciExtensionM(serverP && serverP->Quirk(cSatipServer::eSatipQuirkUseXCI) ? trVDR("yes") : trVDR("no")),
+  ciExtensionM(serverP && serverP->HasCI() ? trVDR("yes") : trVDR("no")),
   createdM(serverP ? serverP->Created() : 0)
 {
   SetMenuCategory(mcSetupPlugins);
diff --git a/socket.c b/socket.c
index 358d506..29c2602 100644
--- a/socket.c
+++ b/socket.c
@@ -129,19 +129,24 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
     if (len > 0)
        return len;
     } while (len > 0);
-  ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1);
+  ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
   return 0;
 }
 
 int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP)
 {
   debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP);
-#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,12)
+  int count = -1;
   // Error out if socket not initialized
   if (socketDescM <= 0) {
      error("%s Invalid socket", __PRETTY_FUNCTION__);
      return -1;
      }
+  if (!bufferAddrP || !elementRecvSizeP || !elementCountP || !elementBufferSizeP) {
+     error("%s Invalid parameter(s)", __PRETTY_FUNCTION__);
+     return -1;
+     }
+#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,12)
   // Initialize iov and msgh structures
   struct mmsghdr mmsgh[elementCountP];
   struct iovec iov[elementCountP];
@@ -154,14 +159,12 @@ int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRec
       }
 
   // Read data from socket as a set
-  int count = -1;
-  if (socketDescM && bufferAddrP && elementRecvSizeP && (elementCountP > 0) && (elementBufferSizeP > 0))
-     count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL);
+  count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL);
   ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1);
   for (int i = 0; i < count; ++i)
       elementRecvSizeP[i] = mmsgh[i].msg_len;
 #else
-  int count = 0;
+  count = 0;
   while (count < (int)elementCountP) {
         int len = Read(bufferAddrP + count * elementBufferSizeP, elementBufferSizeP);
         if (len < 0)
diff --git a/tuner.c b/tuner.c
index 5c770bf..07be861 100644
--- a/tuner.c
+++ b/tuner.c
@@ -25,8 +25,8 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
   rtcpM(*this),
   streamAddrM(""),
   streamParamM(""),
-  currentServerM(NULL),
-  nextServerM(NULL),
+  currentServerM(NULL, deviceP.GetId(), 0),
+  nextServerM(NULL, deviceP.GetId(), 0),
   mutexM(),
   reConnectM(),
   keepAliveM(),
@@ -40,6 +40,7 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
   hasLockM(false),
   signalStrengthM(-1),
   signalQualityM(-1),
+  frontendIdM(-1),
   streamIdM(-1),
   pmtPidM(-1),
   addPidsM(),
@@ -118,7 +119,7 @@ void cSatipTuner::Action(void)
                // Read reception statistics via DESCRIBE and RTCP
                if (hasLockM || ReadReceptionStatus()) {
                   // Quirk for devices without valid reception data
-                  if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) {
+                  if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkForceLock)) {
                      hasLockM = true;
                      signalStrengthM = eDefaultSignalStrength;
                      signalQualityM = eDefaultSignalQuality;
@@ -196,15 +197,15 @@ bool cSatipTuner::Connect(void)
      else if (rtspM.Options(*connectionUri)) {
         cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
         // Flush any old content
-        rtpM.Flush();
-        rtcpM.Flush();
+        //rtpM.Flush();
+        //rtcpM.Flush();
         if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) {
            keepAliveM.Set(timeoutM);
-           if (nextServerM) {
-              cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
+           if (nextServerM.IsValid()) {
               currentServerM = nextServerM;
-              nextServerM = NULL;
+              nextServerM.Reset();
               }
+           currentServerM.Attach();
            return true;
            }
         }
@@ -234,9 +235,9 @@ bool cSatipTuner::Disconnect(void)
   hasLockM = false;
   signalStrengthM = -1;
   signalQualityM = -1;
+  frontendIdM = -1;
 
-  if (currentServerM)
-     cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
+  currentServerM.Detach();
   statusUpdateM.Set(0);
   timeoutM = eMinKeepAliveIntervalMs;
   pmtPidM = -1;
@@ -285,6 +286,9 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
      if (c)  {
         int value;
 
+        // feID:
+        frontendIdM = atoi(c + 7);
+
         // level:
         // Numerical value between 0 and 255
         // An incoming L-band satellite signal of
@@ -330,7 +334,7 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
   cMutexLock MutexLock(&mutexM);
   debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM);
   sessionM = sessionP;
-  if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
+  if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
      rtspM.SetSession(SkipZeroes(*sessionM));
   timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
 }
@@ -341,15 +345,15 @@ int cSatipTuner::GetId(void)
   return deviceIdM;
 }
 
-bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
+bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP)
 {
-  debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, parameterP, indexP, deviceIdM);
+  debug1("%s (%d, %s, %d) [device %d]", __PRETTY_FUNCTION__, transponderP, parameterP, indexP, deviceIdM);
   cMutexLock MutexLock(&mutexM);
   if (serverP) {
-     nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
-     if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
+     nextServerM.Set(serverP, transponderP);
+     if (!isempty(*nextServerM.GetAddress()) && !isempty(parameterP)) {
         // Update stream address and parameter
-        streamAddrM = rtspM.RtspUnescapeString(nextServerM->Address());
+        streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress());
         streamParamM = rtspM.RtspUnescapeString(parameterP);
         // Reconnect
         RequestState(tsSet, smExternal);
@@ -390,8 +394,8 @@ bool cSatipTuner::UpdatePids(bool forceP)
   if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
       !isempty(*streamAddrM) && (streamIdM > 0)) {
      cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
-     bool useci = (SatipConfig.GetCIExtension() && !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkUseXCI)));
-     bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids));
+     bool useci = (SatipConfig.GetCIExtension() && currentServerM.HasCI());
+     bool usedummy = currentServerM.IsQuirk(cSatipServer::eSatipQuirkPlayPids);
      if (forceP || usedummy) {
         if (pidsM.Size())
            uri = cString::sprintf("%s?pids=%s", *uri, *pidsM.ListPids());
@@ -558,6 +562,12 @@ const char *cSatipTuner::TunerStateString(eTunerState stateP)
   return "---";
 }
 
+int cSatipTuner::FrontendId(void)
+{
+  debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
+  return frontendIdM;
+}
+
 int cSatipTuner::SignalStrength(void)
 {
   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
@@ -579,7 +589,7 @@ bool cSatipTuner::HasLock(void)
 cString cSatipTuner::GetSignalStatus(void)
 {
   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
-  return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
+  return cString::sprintf("lock=%d strength=%d quality=%d frontend=%d", HasLock(), SignalStrength(), SignalQuality(), FrontendId());
 }
 
 cString cSatipTuner::GetInformation(void)
diff --git a/tuner.h b/tuner.h
index aa753f6..8ef0beb 100644
--- a/tuner.h
+++ b/tuner.h
@@ -8,11 +8,11 @@
 #ifndef __SATIP_TUNER_H
 #define __SATIP_TUNER_H
 
-#include <vdr/config.h> // APIVERSNUM
 #include <vdr/thread.h>
 #include <vdr/tools.h>
 
 #include "deviceif.h"
+#include "discover.h"
 #include "rtp.h"
 #include "rtcp.h"
 #include "rtsp.h"
@@ -27,33 +27,6 @@ private:
   }
 
 public:
-#if defined(APIVERSNUM) && APIVERSNUM < 20107
-  int IndexOf(const int &pidP)
-  {
-    for (int i = 0; i < Size(); ++i) {
-        if (pidP == At(i))
-           return i;
-        }
-    return -1;
-  }
-  bool RemoveElement(const int &pidP)
-  {
-    int i = IndexOf(pidP);
-    if (i >= 0) {
-       Remove(i);
-       return true;
-       }
-    return false;
-  }
-  bool AppendUnique(int pidP)
-  {
-    if (IndexOf(pidP) < 0) {
-       Append(pidP);
-       return true;
-       }
-    return false;
-  }
-#endif
   void RemovePid(const int &pidP)
   {
     if (RemoveElement(pidP))
@@ -76,6 +49,29 @@ public:
   }
 };
 
+class cSatipTunerServer
+{
+private:
+  cSatipServer *serverM;
+  int deviceIdM;
+  int transponderM;
+
+public:
+  cSatipTunerServer(cSatipServer *serverP, const int deviceIdP, const int transponderP) : serverM(serverP), deviceIdM(deviceIdP), transponderM(transponderP) {}
+  ~cSatipTunerServer() {}
+  cSatipTunerServer(const cSatipTunerServer &objP) { serverM = NULL; deviceIdM = -1; transponderM = 0; }
+  cSatipTunerServer& operator= (const cSatipTunerServer &objP) { serverM = objP.serverM; deviceIdM = objP.deviceIdM; transponderM = objP.transponderM; return *this; }
+  bool IsValid(void) { return !!serverM; }
+  bool IsQuirk(int quirkP) { return (serverM && cSatipDiscover::GetInstance()->IsServerQuirk(serverM, quirkP)); }
+  bool HasCI(void) { return (serverM && cSatipDiscover::GetInstance()->HasServerCI(serverM)); }
+  void Attach(void) { if (serverM) cSatipDiscover::GetInstance()->AttachServer(serverM, deviceIdM, transponderM); }
+  void Detach(void) { if (serverM) cSatipDiscover::GetInstance()->DetachServer(serverM, deviceIdM, transponderM); }
+  void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; }
+  void Reset(void) { serverM = NULL; transponderM = 0; }
+  cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; }
+  cString GetInfo(void) { return cString::sprintf("server=%s deviceid=%d transponder=%d", serverM ? "assigned" : "null", deviceIdM, transponderM); }
+};
+
 class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf
 {
 private:
@@ -100,8 +96,8 @@ private:
   cSatipRtcp rtcpM;
   cString streamAddrM;
   cString streamParamM;
-  cSatipServer *currentServerM;
-  cSatipServer *nextServerM;
+  cSatipTunerServer currentServerM;
+  cSatipTunerServer nextServerM;
   cMutex mutexM;
   cTimeMs reConnectM;
   cTimeMs keepAliveM;
@@ -115,6 +111,7 @@ private:
   bool hasLockM;
   int signalStrengthM;
   int signalQualityM;
+  int frontendIdM;
   int streamIdM;
   int pmtPidM;
   cSatipPid addPidsM;
@@ -139,10 +136,11 @@ public:
   cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP);
   virtual ~cSatipTuner();
   bool IsTuned(void) const { return (currentStateM >= tsTuned); }
-  bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP);
+  bool SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP);
   bool SetPid(int pidP, int typeP, bool onP);
   bool Open(void);
   bool Close(void);
+  int FrontendId(void);
   int SignalStrength(void);
   int SignalQuality(void);
   bool HasLock(void);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git



More information about the pkg-vdr-dvb-changes mailing list