cec: validate the input in CCECProcessor::IsActiveSource(). fixes potential crash...
[deb_libcec.git] / src / lib / CECProcessor.cpp
index 9b44d3b1da22c2a2f78a04e1ac345878e15c2c9a..c7d586e79cce42ab39e061a69b419ebbf786d3f6 100644 (file)
@@ -153,8 +153,6 @@ void CCECProcessor::Close(void)
 
   if (bClose && m_communication)
   {
-    m_communication->PersistConfiguration(&m_configuration);
-    m_communication->Close();
     delete m_communication;
     m_communication = NULL;
   }
@@ -176,18 +174,11 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
     m_bConnectionOpened = (m_communication != NULL);
   }
 
-  /* check for an already opened connection */
-  if (m_communication->IsOpen())
-  {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "connection already opened");
-    return bReturn;
-  }
-
   CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
 
   /* open a new connection */
   unsigned iConnectTry(0);
-  while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open(this, (timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
+  while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open((timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
   {
     CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
     m_communication->Close();
@@ -201,7 +192,18 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
   }
 
   if (m_configuration.bGetSettingsFromROM == 1)
-    m_communication->GetConfiguration(&m_configuration);
+  {
+    libcec_configuration config;
+    config.Clear();
+    m_communication->GetConfiguration(&config);
+
+    CLockObject lock(m_mutex);
+    if (!config.deviceTypes.IsEmpty())
+      m_configuration.deviceTypes = config.deviceTypes;
+    if (config.iPhysicalAddress > 0)
+      m_configuration.iPhysicalAddress = config.iPhysicalAddress;
+    snprintf(m_configuration.strDeviceName, 13, "%s", config.strDeviceName);
+  }
 
   return bReturn;
 }
@@ -514,7 +516,8 @@ bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
 {
   bool bReturn(false);
 
-  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
+  // suppress polls when searching for a device
+  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath, false, true);
   if (device)
   {
     device->SetActiveSource();
@@ -721,7 +724,16 @@ bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpda
     SetActiveView();
 
   if (bReturn)
-    CLibCEC::ConfigurationChanged(m_configuration);
+  {
+    libcec_configuration config;
+    {
+      CLockObject lock(m_mutex);
+      config = m_configuration;
+    }
+
+    PersistConfiguration(&config);
+    CLibCEC::ConfigurationChanged(config);
+  }
 
   return bReturn;
 }
@@ -779,7 +791,7 @@ uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
   return status;
 }
 
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */, bool bSuppressPoll /* = false */) const
 {
   if (m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
     return m_busDevices[m_configuration.logicalAddresses.primary];
@@ -787,7 +799,7 @@ CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddre
   CCECBusDevice *device = NULL;
   for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
   {
-    if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
+    if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh, bSuppressPoll) == iPhysicalAddress)
     {
       device = m_busDevices[iPtr];
       break;
@@ -882,7 +894,9 @@ cec_logical_address CCECProcessor::GetActiveSource(void)
 
 bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
 {
-  return m_busDevices[iAddress]->IsActiveSource();
+  return iAddress > CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST ?
+    m_busDevices[iAddress]->IsActiveSource() :
+    false;
 }
 
 bool CCECProcessor::Transmit(const cec_command &data)
@@ -1479,7 +1493,7 @@ bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
     IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
     CTimeout timeout(10000);
     int iConnectTry(0);
-    while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(NULL, (timeout.TimeLeft() / CEC_CONNECT_TRIES)), true) == false)
+    while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
     {
       CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
       comm->Close();
@@ -1505,7 +1519,8 @@ bool CCECProcessor::PingAdapter(void)
 
 void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
 {
-  m_busDevices[destination]->HandlePoll(initiator);
+  if (destination < CECDEVICE_BROADCAST)
+    m_busDevices[destination]->HandlePollFrom(initiator);
 }
 
 bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
@@ -1525,12 +1540,15 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   CCECBusDevice *primary = IsRunning() ? GetPrimaryDevice() : NULL;
   cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
   m_configuration.clientVersion  = configuration->clientVersion;
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString((cec_client_version)configuration->clientVersion));
 
   // client version 1.5.0
 
   // device types
   bool bDeviceTypeChanged = IsRunning () && m_configuration.deviceTypes != configuration->deviceTypes;
   m_configuration.deviceTypes = configuration->deviceTypes;
+  if (bDeviceTypeChanged)
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(configuration->deviceTypes[0]));
 
   bool bPhysicalAddressChanged(false);
 
@@ -1543,6 +1561,8 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
     {
       if (IsRunning())
         CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%4x'", __FUNCTION__, iPhysicalAddress);
+      else
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using physical address '%x'", __FUNCTION__, iPhysicalAddress);
       bPhysicalAddressChanged = (m_configuration.iPhysicalAddress != iPhysicalAddress);
       m_configuration.iPhysicalAddress = iPhysicalAddress;
       m_configuration.iHDMIPort = 0;
@@ -1558,8 +1578,7 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
       bPhysicalAddressChanged = IsRunning() && m_configuration.iPhysicalAddress != configuration->iPhysicalAddress;
     if (bPhysicalAddressChanged)
     {
-      if (IsRunning())
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using physical address '%4x'", __FUNCTION__, configuration->iPhysicalAddress);
+      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - physical address '%x'", __FUNCTION__, configuration->iPhysicalAddress);
       m_configuration.iPhysicalAddress = configuration->iPhysicalAddress;
     }
   }
@@ -1569,20 +1588,17 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   {
     // base device
     bHdmiPortChanged = IsRunning() && m_configuration.baseDevice != configuration->baseDevice;
-    if (IsRunning())
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using base device '%x'", __FUNCTION__, (int)configuration->baseDevice);
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using base device '%x'", __FUNCTION__, (int)configuration->baseDevice);
     m_configuration.baseDevice = configuration->baseDevice;
 
     // hdmi port
     bHdmiPortChanged |= IsRunning() && m_configuration.iHDMIPort != configuration->iHDMIPort;
-    if (IsRunning())
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using HDMI port '%d'", __FUNCTION__, configuration->iHDMIPort);
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using HDMI port '%d'", __FUNCTION__, configuration->iHDMIPort);
     m_configuration.iHDMIPort = configuration->iHDMIPort;
   }
   else
   {
-    if (IsRunning())
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
     m_configuration.baseDevice = CECDEVICE_UNKNOWN;
     m_configuration.iHDMIPort  = 0;
   }
@@ -1590,6 +1606,7 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged;
 
   // device name
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, configuration->strDeviceName);
   snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
   if (primary && !primary->GetOSDName().Equals(m_configuration.strDeviceName))
   {
@@ -1599,6 +1616,7 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   }
 
   // tv vendor id override
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString((cec_vendor_id)configuration->tvVendor));
   if (m_configuration.tvVendor != configuration->tvVendor)
   {
     m_configuration.tvVendor= configuration->tvVendor;
@@ -1614,7 +1632,6 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   }
 
   // just copy these
-  m_configuration.clientVersion        = configuration->clientVersion;
   m_configuration.bUseTVMenuLanguage   = configuration->bUseTVMenuLanguage;
   m_configuration.bActivateSource      = configuration->bActivateSource;
   m_configuration.bGetSettingsFromROM  = configuration->bGetSettingsFromROM;
@@ -1637,7 +1654,11 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   if (m_configuration.deviceTypes.IsEmpty())
     m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
 
-  if (bReinit)
+  // persist the configuration
+  if (IsRunning())
+    m_communication->PersistConfiguration(&m_configuration);
+
+  if (bReinit || m_configuration.logicalAddresses.IsEmpty())
   {
     if (bDeviceTypeChanged)
       return ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);