@@ -396,9 +396,81 @@ void OperationalSessionSetup::NotifyConnectionCallbacks(Cancelable & failureRead
396
396
System::Clock::Milliseconds16 requestedBusyDelay)
397
397
{
398
398
//
399
- // If we encountered no error, go ahead and call all success callbacks. Otherwise,
400
- // call the failure callbacks.
399
+ // Go ahead and call our callbacks. We want to walk through all the lists,
400
+ // because we need to Cancel() each callback no matter what. Which
401
+ // callbacks we then call depends on whether we have encountered an error.
401
402
//
403
+ while (successReady.mNext != &successReady)
404
+ {
405
+ // We expect that we only have callbacks if we are not performing just address update.
406
+ VerifyOrDie (!performingAddressUpdate);
407
+ Callback::Callback<OnDeviceConnected> * cb = Callback::Callback<OnDeviceConnected>::FromCancelable (successReady.mNext );
408
+
409
+ cb->Cancel ();
410
+ if (error == CHIP_NO_ERROR)
411
+ {
412
+ VerifyOrDie (exchangeMgr);
413
+ // We know that we for sure have the SessionHandle in the successful
414
+ // case, and the session is active.
415
+ VerifyOrDie (optionalSessionHandle.Value ()->AsSecureSession ()->IsActiveSession ());
416
+ cb->mCall (cb->mContext , *exchangeMgr, optionalSessionHandle.Value ());
417
+
418
+ // That call might have made the session inactive. If it did, then
419
+ // we should not call any more success callbacks, since we do not in
420
+ // fact have an active session for them, and if they try to put the
421
+ // session in a holder that will fail, and then trying to use the
422
+ // holder as if it has a session will crash. But we should also try
423
+ // to make sure we don't call failure callbacks the correspond to
424
+ // the success callbacks we already called, since their context
425
+ // might be dead.
426
+ //
427
+ // What that means is that after every success callback we should
428
+ // remove the corresponding failure callbacks from our lists.
429
+ // Unfortunately, callers are allowed to pass null callbacks, so we
430
+ // can't just remove the first one, and in any case we have multiple
431
+ // kinds of error callbacks. But what we should probably do is just
432
+ // remove the first callback that has the same context as the
433
+ // callback we just called. And if there is more than one that
434
+ // matches, clearly the API consumer was not expecting to delete
435
+ // itself when called, so we're OK with only dropping the first one.
436
+ //
437
+ // This would all be simpler if we just had a single callback per
438
+ // API consumer that communicated success-or-failure in a single
439
+ // call...
440
+ for (auto * failureCancelable = failureReady.mNext ; failureCancelable != &failureReady;
441
+ failureCancelable = failureCancelable->mNext )
442
+ {
443
+ auto * failureCallback = Callback::Callback<OnDeviceConnectionFailure>::FromCancelable (failureCancelable);
444
+ if (failureCallback->mContext == cb->mContext )
445
+ {
446
+ failureCallback->Cancel ();
447
+ break ;
448
+ }
449
+ }
450
+
451
+ for (auto * setupFailureCancelable = setupFailureReady.mNext ; setupFailureCancelable != &setupFailureReady;
452
+ setupFailureCancelable = setupFailureCancelable->mNext )
453
+ {
454
+ auto * setupFailureCallback = Callback::Callback<OnSetupFailure>::FromCancelable (setupFailureCancelable);
455
+ if (setupFailureCallback->mContext == cb->mContext )
456
+ {
457
+ setupFailureCallback->Cancel ();
458
+ break ;
459
+ }
460
+ }
461
+
462
+ if (!optionalSessionHandle.Value ()->AsSecureSession ()->IsActiveSession ())
463
+ {
464
+ // Set error to a non-success value so that we stop calling
465
+ // success callbacks. We will call the relevant remaining error
466
+ // callbacks in the blocks below.
467
+ ChipLogError (Discovery, " Success callback for connection to " ChipLogFormatScopedNodeId " tore down session" ,
468
+ ChipLogValueScopedNodeId (peerId));
469
+ error = CHIP_ERROR_CONNECTION_ABORTED;
470
+ }
471
+ }
472
+ }
473
+
402
474
while (failureReady.mNext != &failureReady)
403
475
{
404
476
// We expect that we only have callbacks if we are not performing just address update.
@@ -435,21 +507,6 @@ void OperationalSessionSetup::NotifyConnectionCallbacks(Cancelable & failureRead
435
507
cb->mCall (cb->mContext , failureInfo);
436
508
}
437
509
}
438
-
439
- while (successReady.mNext != &successReady)
440
- {
441
- // We expect that we only have callbacks if we are not performing just address update.
442
- VerifyOrDie (!performingAddressUpdate);
443
- Callback::Callback<OnDeviceConnected> * cb = Callback::Callback<OnDeviceConnected>::FromCancelable (successReady.mNext );
444
-
445
- cb->Cancel ();
446
- if (error == CHIP_NO_ERROR)
447
- {
448
- VerifyOrDie (exchangeMgr);
449
- // We know that we for sure have the SessionHandle in the successful case.
450
- cb->mCall (cb->mContext , *exchangeMgr, optionalSessionHandle.Value ());
451
- }
452
- }
453
510
}
454
511
455
512
void OperationalSessionSetup::OnSessionEstablishmentError (CHIP_ERROR error, SessionEstablishmentStage stage)
0 commit comments