Closed ivmarkov closed 1 month ago
@kedars I think I just confirmed even a stronger statement by looking at the C++ SDK: The implementation of subscriptions in the SDK is such that the unsolicited subscription data reports always happen not just on behalf of the same fabric+node+IP address, but on behalf of the same session. Look here: https://github.com/project-chip/connectedhomeip/blob/master/src/app/reporting/Engine.cpp#L514
They are basically re-using the read handler on which the original subscription request came, and this read handler is bound to a session. So in a way, if the session is gone, the subscription created via this session is gone too.
I can easily do a similar change in our code base (i.e. binding the subscription to a concrete session).
Shall I?
More research:
While I'm now 100% sure the C++ SDK by default re-uses the read handler and its attached session, there is an optional #ifdef
-ed part which allows subscriptions to be "persisted".
When a subscription is persisted (say, for an ICD device - in fact I think that's the only use case for subscription persistence) and then de-persisted, what happens is that a suitable session for that subscription is searched for (and if not found - created - which we still do not support as that would imply mDNS lookups).
Now, the search for a suitable session is done only by using fabric index and peer node ID - 100% as we do it too.
The major difference however is that if the subscriptions are persisted, then the sessions are persisted too (or just removed). However, I don't think session persistence involves persistence of the IP address. So on de-persisting, the C++ SDK will do a fresh mDNS lookup of a new IP address for the de-persisted session/subscription.
So my hypothesis is, if the persistence code kicks-in, due to the mDNS lookup we'll not get into our corner case because I've checked - the IPv6 address responding to the mDNS lookups is not the problematic one from my earlier analysis.
You've already discovered the persistent subscriptions; that was the only scenario I was thinking where this might be required. But anyway discovering the IP Address based on its mDNS name is the right thing to do.
I am also doing an experiment to see how the C++ SDK and Apple devices behave in the scenario that you highlighted. Since they share node-ids across devices that have the same sign-in. But I am not able to get requests from the second device (iPhone) in my setup. It always comes from the hub.
Regardless, storing the IP Address feels definitely like the wrong thing to do (The Address itself can change across device-resets or others, so relying on discovery is more reliable).
@andreilitvin any observations from you on this?
What about the other approach that you would see shortly in a forthcoming PR which is for something related? I.e.:
This way I think we are as close to the C++ SDK behavior as possible, and also future-proof once we implement mDNS lookups
Copying the part of #181 which is still unresolved here, to keep the discussion open:
Apple Matter is a bit weird. Putting aside the fact that we are commissioned into two fabrics, the other weird thing that happens is that once we are commissioned in the second fabric, they are communicating with us on behalf of TWO different IP addresses, which - however - do represent the same node+fabric ID?!
fe80::8d7:cf23:8b0b:f715%2
- in fact this guy has two different nodes, one on fabric 1, and another on fabric 2 - see our session dump belowfe80::416:93dd:216a:d50a%2
- this guy has the only one node on fabric 1 (or so we know), but its node on Fabric 1 is the same as the node of the previous IP!And now the real weird part: we receive a subscription request from IP Address 2 and this all goes well. But when the time comes to report on that subscription in some seconds / minutes and initiate a new exchange, it just so happens that we select an existing session for "IP Address 1" instead, because we are just looking for a session matching the fabric index (=1) and the node ID. And since the first address also has created sessions to us on behalf of fabric 1, we just happen to pick a session for IP Address 1, even if the subscription came from IP Address 2.
... and get "Invalid Subscription" from the other peer.
Now, if we pick a session based on fabric index + peer node ID + remote address, then we select a session with "IP Address 2" (the address from where the subscription came) and all is well!
So @kedars what do you think is going on? Shall I just also keep the IP address in the subscription data and do a match by that address too? This works (confirmed) but sounds a bit weird. Am I missing something in the spec?
Session dump: