GENA (General Event Notification Architecture)

I just don’t understand your conclusion: why should I be disappointed ?

What is important is that the UPnP proxy already implements this “just in case” queuing of notifications for unknown SIDs. In this case, I understand there is no risk to loose notification.

Hi futzle.

I discovered a minor problem. Maybe you could make an improvment, I don’t know.

I had 2 Sonos devices with event registration through the proxy.
I deleted one of these devices.
Now I get some errors like that:

02 09/21/13 13:48:18.846 JobHandler_LuaUPnP::HandleActionRequest can't handle service: urn:micasaverde-com:serviceId:Sonos1 <0x2f7be680> 02 09/21/13 13:48:18.846 JobHandler_LuaUPnP::RunAction device -1 action urn:micasaverde-com:serviceId:Sonos1/NotifyAVTransportChange failed with 401/Invalid service/action/device <0x2f7be680>

My hypothesis is that the proxy does not erase its table even when reloading lua and so the proxy tries to redirect events to a Sonos device that does no more exist.
If I am right, the errors should stop as soon as the subscription will expire (max 1 hour).

Would it be possible and a good idea that you first check that the device still exists before redirecting something to it ?

Additional thought:

  • at plugin restart, you could check for each redirection rule if the Vera device exists; if not, you would delete the redirection rule
  • you could add a new user button/action to erase all registrations
  • it would be really cool if you could add a new tab on the device that would list all the current proxy subscriptions.

[quote=“lolodomo”]My hypothesis is that the proxy does not erase its table even when reloading lua and so the proxy tries to redirect events to a Sonos device that does no more exist.
If I am right, the errors should stop as soon as the subscription will expire (max 1 hour).

Would it be possible and a good idea that you first check that the device still exists before redirecting something to it ?[/quote]

I agonized about this problem when I first noticed it months ago. Let me explain the thought process that led to me leaving it the way it is as the lesser of two evils. Perhaps you can talk me around, if you can suggest a way to overcome the problems.

Luup restarts are sudden. There’s no time for a client UPnP plugin (like a Sonos or WeMo plugin) to cancel its own subscriptions. The plugins are just reset and they shortly run their startup code again. So the only way for old subscriptions to be cancelled is for some code to do it as part of the Luup restart. Probably in the UPnP proxy plugin device itself, since that’s the only one that is guaranteed to exist. Especially if you’ve just deleted a device.

During a Luup restart, I can’t control the order in which the devices run their startup code. If the UPnP proxy plugin tells the proxy process to flush its memory of past subscriptions then there’s a risk that it’ll wipe out a subscription made seconds ago in parallel by the Sonos plugin that just started up.

I judged that a few rogue notifications, for only an hour, which will be ignored anyway, was safer than risking a race condition that (only sometimes) killed valid notifications.

If the proxy process could get back a “no such device” or “no such action” message as an error, then it could remove the notification from its table. But the LuaUPnP call_action request always returns 200 OK. So that won’t work.

Another possibility that I just thought of tonight is for each notification to be accompanied with an epoch, a number that can identify a particular run of LuaUPnP. Restart Luup, and you get a new epoch. Then, as the UPnP proxy plugin runs its startup Lua, it could tell the background process what the new epoch is, and the background process could delete any notification belonging to a different epoch. The “loadtime” attribute in lu_sdata is perfect for this, because it changes only when the Luup engine reloads. Unfortunately it is not exposed to the Lua runtime, and forcing plugins to do an HTTP request to get lu_sdata seems like a lot of trouble just to make a cleaner log.

So there we are. On the one hand, ugly messages in the log. On the other, more complexity for client plugins. What would you do?

Hard. The list of registrations is known only to the background proxy process. The plugin Lua doesn’t have access to them. It could query the background process to get that list, I suppose. But the payoff of cleaner logs for an hour doesn’t justify the extra complexity or the effort in adding a new RESTful interface to the proxy for me. Patches welcome, as they say.

- you could add a new user button/action to erase all registrations

Easy. Probably also a good idea for debugging. Simpler than running /etc/init.d/upnp-event-proxy restart.

- it would be really cool if you could add a new tab on the device that would list all the current proxy subscriptions.

Yes, it would. But harder than you think. You can’t just query the proxy process for the subscriptions directly from JavaScript because of restrictions on cross-site scripting (in this case, cross-port scripting). So the UPnP proxy plugin device would have to act as a … proxy and forward requests on to the background process. It’s probably doable but I wasn’t willing to expend the effort on coding it, particularly because it looked like it would increase the risk of deadlock on the actual functioning of the background process. If all you are after is a developer tool then there are probably safer ways to get that list, say, through a command-line curl command.

Ok Futzle, I understand.

For the restart process, in the Sonos plugin, I unsubscribe properly as soon as I receive a notification from an old subscription. The only case that does not work is of course when a device is suppressed, -but that is not something that will happen often in a normal situation).

At least now I have the command to init the proxy: /etc/init.d/upnp-event-proxy restart.
It could help developers in certain circonstancies.

Hi futzle.

I think I discovered a bug in the proxy.
It happens in a non common case, when you have several Vera devices attached to the same UPnP device.
In this case, it is very probable that the subscription ID is the same as the request comes from the same IP (vera IP).

I have not checked your code, but my feeling is that you don’t dispatch the events to all the Vera devices. One of my Vera device is no more updated in this case. I should confirm later that the device is not notified.

And even more, when cancelling a subscription, we should be able to cancel only for a particular Vera device. If the proxy has in its table another Vera device with the same subscription ID, you should just update your proxy table without sending a subscription deletion to the UPnP device.

I hope I am clear in my explanations and my hypothesis relative to the proxy behaviour are correct.

Hi lolodomo,

Yeah, support for multiple Veras is half-baked. I made a start on it but since I’ve only got one (plugged-in) Vera I had no way to test it. So I left it unfinished. It may well also have faulty design decisions.

I’m happy for you to take the bull by the horns and complete multi-Vera support in the proxy. Whatever you change in the I will merge to official branch on apps.mios.com.

@futzle: I am a little lost with your code. Why have you a table variables and a table proxy for a subscription ? variables is to store only the variables name ? But we can have several subscriptions for the same variable name, for example LastChange.
Except that point that is not clear for me, after taking a quick look at your code, it looks like you are storing several entries if I call the same subscription for different devices. So normally each devices should then be notified.

[quote=“lolodomo, post:49, topic:171160”]@futzle: I am a little lost with your code. Why have you a table variables and a table proxy for a subscription ? variables is to store only the variables name ? But we can have several subscriptions for the same variable name, for example LastChange.
Except that point that is not clear for me, after taking a quick look at your code, it looks like you are storing several entries if I call the same subscription for different devices. So normally each devices should then be notified.[/quote]

That’s the intention. The [tt]variables[/tt] table is to store the most-recently received variables that came from the UPnP device, and their current values. It’s keyed on the variable name. The [tt]proxy[/tt] table is an ordered list of tables, one for each notification that has to be sent back to the MiOS plugin. Each member of [tt]proxy[/tt] has keys [tt]name[/tt], [tt]host[/tt], [tt]deviceId[/tt], [tt]serviceId[/tt], [tt]action[/tt], [tt]parameter[/tt], [tt]sidParameter[/tt].

It’s possible for a variable to be in [tt]variables[/tt] but never referenced in [tt]proxy[/tt]. That’ll happen when the UPnP device has sent a NOTIFY for a service and included variables that I didn’t care about. It can also happen in the race condition when the UPnP device is responding to an initial SUBSCRIBE but the MiOS device hasn’t yet had time to tell the UPnP Proxy daemon about the subscription.

It’s possible for the same variable to be mentioned several times in the [tt]proxy[/tt] table. Perhaps two different MiOS devices are both interested in the same UPnP variable and have both subscribed to it. Perhaps two different Veras are subscribing to the same event. It’s this latter case that is in need of further coding. The former (where two MiOS devices are both subscribed) I never really tested, but it was always in my design.

It is the former case that interests me.
First I will check/add traces in my plugin to be sure that the problem is not in my plugin.

Here is what happens:

  1. A first device asks the proxy to subscribe to an event => I get a SID. Notifications are received normally by this device
  2. A second device asks the proxy to subscribe to the same event (same IP/port/variable) => I get a new SID. ; Notifications are received normally by this device
  3. Problem: the first device does no more receive notifications

I have disabled in my code all subscription cancelations.

So it let me think that when the second device subscribes the event, the proxy looses the subscription of the first device.

Or is it due to the new SID ? Maybe the UPnP device (Sonos in my case) does not handle 2 different SID for the same control IP (Vera) ?

Interesting. You can test it easily enough by running the UPnP proxy directly from the Vera root shell, and watching its debug statements print to the screen.

I’m hoping that the proxy is still getting both NOTIFY events but isn’t passing one on to the MiOS device. That can at least be fixed in our code.

Interesting. You can test it easily enough by running the UPnP proxy directly from the Vera root shell, and watching its debug statements print to the screen.

I’m hoping that the proxy is still getting both NOTIFY events but isn’t passing one on to the MiOS device. That can at least be fixed in our code.[/quote]

Unfortunately it looks like my last idea was the good one.
When I subscribe again to a Sonos device, the previous subscription is no more notified.
In my plugins, I track bad SID and what is strange is that sometimes I see bad SID after a lua reload. That would mean that in thi case I have several active subscriptions for the same device. But it is not systematic.

I will check if this behaviour is specific to Sonos devices or more general.

There are not a lot of things I can setup in the SUBSCRIBE message. Do you think a different callback header could help to avoid that behaviour ?
And is it something possible to change ? I mean for example using /upnp/event/ rather than /upnp/event

The important to have in my mind is that there are nothing wrong in our plugins. It is just another limit to know (if two Mios devices are attached to the same UPnP device, only one of them will be notified - the last one having subscribed the events).

Doing a bit of searching on the Sonos forums, it looks like the Sonos (incorrectly) treats subscriptions on a per-IP basis. If that’s true then I don’t like your chances.

Doing a bit of searching on the Sonos forums, it looks like the Sonos (incorrectly) treats subscriptions on a per-IP basis. If that’s true then I don’t like your chances.[/quote]

Ok, that’s a good information.
Later I will check whether the behaviour is better with XBMC and WMP and confirm that your plugin correctly handles two subscriptions from two Mios devices for the same UPnP device.

That’s now confirmed, I just lost my time !

I noticed no problem using two Mios devices “connected” to XBMC. Same with Windows Media Player.

As you discovered, it seems a bug in Sonos.

So sorry for the confusion, there is no bug in your proxy, everything is correctly managed.

@futzle: my UPnP event proxy is suddenly crashing, systematically. :frowning:

Here are the logs:

/usr/bin/lua: /tmp/upnp-event-proxy.lua:248: error closing parser: not well-formed (invalid token) stack traceback: [C]: in function 'close' /tmp/upnp-event-proxy.lua:248: in function 'close' /tmp/upnp-event-proxy.lua:361: in function </tmp/upnp-event-proxy.lua:353> (tail call): ? /tmp/upnp-event-proxy.lua:487: in main chunk [C]: ?
Any idea ?

Problem was solved by killing the UPnP device (XBMC) that was notifying the Vera … to stop the notify.

I started again and now the proxy is alive.

Maybe there is a way to secure your code ?

Ouch. That means the UPnP device might be sending badly-formed XML. It’s the included LXP library that actually does the parsing. Making the UPnP proxy resilient in the face of badly-formed XML is going to be tricky, but I agree it should be done. Crashing on bad input is something we accuse Onkyo of doing; we shouldn’t be guilty of it ourselves.