500/503 errors on git master and noson-2.2.0
I'll debug this a bit more, but just to have an issue to track this (or in case you know what it is): I've started getting 500 during discovery, and then continously (SONOS)WSResponse: server error (503) when the application is running.
Excerpt from the output when starting (replaced the names and stuff for privacy or whatever);
(SONOS)FindDeviceDescription: starting new context
(SONOS)FindDeviceDescription: location url found (http://10.0.x.x:1400/xml/device_description.xml)
(SONOS)FindDeviceDescription: server string found (Linux UPnP/1.0 Sonos/54.2-72031 (ANVIL))
(SONOS)FindDeviceDescription: search target matches
(SONOS)ParseZoneGroupState: new group 'RINCON_001:2937147748' with coordinator 'RINCON_001'
(SONOS)ParseZoneGroupState: new group member 'RINCON_001' (Device1)
(SONOS)ParseZoneGroupState: new group 'RINCON_002:4002351680' with coordinator 'RINCON_002'
(SONOS)ParseZoneGroupState: new group member 'RINCON_002' (Device2)
(SONOS)ParseZoneGroupState: new group 'RINCON_003:1555968828' with coordinator 'RINCON_003'
(SONOS)ParseZoneGroupState: new group member 'RINCON_003' (Device3)
(SONOS)ParseZoneGroupState: topology key 178020472
loadContent: 0x55a6f9987a90 ()
(SONOS)WSResponse: server error (500)
(SONOS)Request: invalid response
(SONOS)GetAvailableServices: query services failed
handleRenderingControlChange: sig=3 volume: 0.990 [1]
create player 1 [Device3]
(SONOS)WSResponse: server error (503)
handleRenderingControlChange: [RINCON_003] sig=2 volume: 34.000 [34]
handleRenderingControlChange: sig=3 volume: 34.000 [34]
handleRenderingControlChange: sig=3 volume: 0.990 [1]
create player 2 [Device2]
handleRenderingControlChange: [RINCON_002] sig=2 volume: 7.000 [7]
handleRenderingControlChange: sig=3 volume: 7.000 [7]
handleRenderingControlChange: sig=3 volume: 0.990 [1]
create player 3 [Device1]
loadContent: 0x55a6f9983ec0 ()
Ok, bumped the debug level up to 6, and the 500 errors during startup comes when it connects to a Sub during startup, and not e. g. a playbar. That is, the first FindDeviceDescription: location url found points to the sub and not one of the "normal" speakers. I'm not sure how it decides which url to connect to?
FWIW the first path it tries to post to that fails is /MusicServices/Control, which makes sense because the sub doesn't support playing music by itself.
Looking in the code I see that it chooses it based on the SERVER in the UDP reply. The easiest fix for just my issue now is probably to check the last part there, the sub seems to report (ANVIL), while the playbar reports ZPS13 and the normal speakers report ZPS9.
But I think the best solution is to get a list of potential URLs in FindDeviceDescription, and check the ServiceList in all of them to find one that supports e. g. /MusicServices/Control.
A more "correct" solution/patch, but the real proper solution would be to have a separate thread reading URLs continously, this patch assumes we get all responses within 1 second (and it always waits 1 second extra);
diff --git noson/src/sonossystem.cpp noson/src/sonossystem.cpp
index 556b93b..207afa8 100644
--- noson/src/sonossystem.cpp
+++ noson/src/sonossystem.cpp
@@ -101,10 +101,16 @@ void System::Debug(int level)
bool System::Discover()
{
- std::string url;
- if (!FindDeviceDescription(url))
+ std::vector<std::string> urls;
+ if (!FindDeviceDescriptions(urls))
return false;
- return Discover(url);
+
+ for (const std::string &url : urls) {
+ if (Discover(url)) {
+ return true;
+ }
+ }
+ return false;
}
bool System::Discover(const std::string& url)
@@ -126,6 +132,13 @@ bool System::Discover(const std::string& url)
SAFE_DELETE(m_deviceProperties);
SAFE_DELETE(m_groupTopology);
+ // music services
+ m_musicServices = new MusicServices(uri.Host(), uri.Port());
+ m_smservices = m_musicServices->GetAvailableServices();
+ if (m_smservices.empty()) {
+ return false;
+ }
+
// subscribe to ZoneGroupTopology events
m_groupTopology = new ZoneGroupTopology(uri.Host(), uri.Port(), m_subscriptionPool, this, CB_ZGTopology);
@@ -152,10 +165,6 @@ bool System::Discover(const std::string& url)
m_serialNumber = vars.GetValue("SerialNumber");
m_softwareVersion = vars.GetValue("SoftwareVersion");
- // music services
- m_musicServices = new MusicServices(uri.Host(), uri.Port());
- m_smservices = m_musicServices->GetAvailableServices();
-
// subscribe to AlarmClock events
m_alarmClock = new AlarmClock(uri.Host(), uri.Port(), m_subscriptionPool, this, CB_AlarmClock);
@@ -615,12 +624,13 @@ RequestBrokerPtr System::GetRequestBroker(const std::string &name)
return m_eventHandler.GetRequestBroker(name);
}
-bool System::FindDeviceDescription(std::string& url)
+bool System::FindDeviceDescriptions(std::vector<std::string>& urls)
{
#define IPBC_ADDR "255.255.255.255"
#define SSDP_ADDR "239.255.255.250"
#define SSDP_STRP "1900"
#define SSDP_NUMP 1900
+#define RESPONSES_TIMEOUT 1000
#define DISCOVER_TIMEOUT 5000
#define DISCOVER_ST "urn:schemas-upnp-org:device:ZonePlayer:1"
#define HTTP_TOKEN_MAXSIZE 20
@@ -644,6 +654,7 @@ bool System::FindDeviceDescription(std::string& url)
sock.SetMulticastTTL(4);
OS::CTimeout timeout(DISCOVER_TIMEOUT);
+ OS::CTimeout responsesTimeout;
while (!ret && timeout.TimeLeft() > 0 && !laddr.empty())
{
std::pair<std::string, unsigned> addr = laddr.front();
@@ -714,7 +725,7 @@ bool System::FindDeviceDescription(std::string& url)
{
DBG(DBG_INFO, "%s: location url found (%s)\n", __FUNCTION__, val);
_context |= 0x8;
- url.assign(val);
+ urls.push_back(val);
}
break;
default:
@@ -727,6 +738,17 @@ bool System::FindDeviceDescription(std::string& url)
DBG(DBG_INFO, "%s: reseting context\n", __FUNCTION__);
_context = 0; // reset context
}
+
+ }
+
+ // If we got a response, we give it one more second to receive potentially additional urls
+ if (_context == 0xF) {
+ if (!responsesTimeout.IsSet()) {
+ responsesTimeout.Set(RESPONSES_TIMEOUT);
+ _context = 0;
+ } else if (responsesTimeout.TimeLeft() > 0) {
+ _context = 0;
+ }
}
}
ret = (_context == 0xF);
diff --git noson/src/sonossystem.h noson/src/sonossystem.h
index 0ad52db..dbca002 100644
--- noson/src/sonossystem.h
+++ noson/src/sonossystem.h
@@ -195,7 +195,7 @@ namespace NSROOT
SMServiceList m_smservices;
- static bool FindDeviceDescription(std::string& url);
+ static bool FindDeviceDescriptions(std::vector<std::string>& urls);
void RevokePlayers();
static void CB_ZGTopology(void* handle);
Hi, I think we could parse the description or topology response to choose the device handling the control service. have you the full messages of the description or topology request ? I had same issue with bridge device which reply to the ssdp request too. Those are discarded in the code of "findDescription".
Hi Martin, I updated the lib to discard some models during the discovery.
https://github.com/janbar/noson/commit/4d30308e03628031832041b7f2d758c17d316d9f
Hope it can help
Sorry for the late reply, but that looks like the best and most pragmatic solution. :-)