@@ -70,26 +70,48 @@ public enum ProxyFilerType {
7070public protocol ProxyFilterDelegate : AnyObject {
7171 /// Method called when the Proxy Filter has been sent to proxy.
7272 ///
73+ /// This method is followed by ``proxyFilterUpdateAcknowledged(type:listSize:)-7hg0l``
74+ /// or ``proxyFilterLimitReached(type:maxSize:)-30217``, depending on the
75+ /// acknowledged list size.
76+ ///
7377 /// - parameters:
7478 /// - type: The current Proxy Filter type.
7579 /// - addresses: The addresses in the filter.
7680 func proxyFilterUpdated( type: ProxyFilerType , addresses: Set < Address > )
7781
78- /// Method called when the Proxy Filter has been acknowledged by proxy.
82+ /// Method called when the Proxy Filter has been acknowledged by proxy
83+ /// and the reported list size is equal to the requested one.
84+ ///
85+ /// In case the reported list size is lower than expected
86+ /// ``proxyFilterLimitReached(type:maxSize:)-7hg0l`` is called
87+ /// instead.
7988 ///
8089 /// - parameters:
8190 /// - type: The current Proxy Filter type.
8291 /// - listSize: The addresses list's size in the filter
8392 func proxyFilterUpdateAcknowledged( type: ProxyFilerType , listSize: UInt16 )
8493
85- /// This method is called when the connected Proxy device supports
86- /// only a single address in the Proxy Filter list.
94+ /// This method is called when the max size of Proxy Filter list has been reached
95+ /// and no more addresses can be added.
96+ ///
97+ /// The delegate can switch to ``ProxyFilerType/rejectList``
98+ /// filter type using ``ProxyFilter/setType(_:)``. This will allow receiving
99+ /// messages sent to more addresses than supported by the ``ProxyFilerType/acceptList``.
87100 ///
88- /// The delegate can switch to `.exclusionList` filter type at that point
89- /// to receive messages sent to addresses other than those that were
90- /// added successfully.
101+ /// - parameters:
102+ /// - type: The current Proxy Filter type.
103+ /// - maxSize: The maximum Proxy Filter list size.
104+ func proxyFilterLimitReached( type: ProxyFilerType , maxSize: UInt16 )
105+
106+ /// This method is called when the max size of Proxy Filter list has been reached
107+ /// and no more addresses can be added.
108+ ///
109+ /// The delegate can switch to ``ProxyFilerType/rejectList``
110+ /// filter type at that point to receive messages sent to addresses other
111+ /// than those that were added successfully.
91112 ///
92113 /// - parameter maxSize: The maximum Proxy Filter list size.
114+ @available ( * , deprecated, message: " Use proxyFilterLimitReached(type:maxSize) instead " )
93115 func limitedProxyFilterDetected( maxSize: Int )
94116}
95117
@@ -99,6 +121,14 @@ public extension ProxyFilterDelegate {
99121 // Do nothing.
100122 }
101123
124+ func proxyFilterLimitReached( type: ProxyFilerType , maxSize: UInt16 ) {
125+ // Do nothing.
126+ }
127+
128+ func proxyFilterUpdateAcknowledged( type: ProxyFilerType , listSize: UInt16 ) {
129+ // Do nothing.
130+ }
131+
102132}
103133
104134/// An enumeration for different initial configurations of the Proxy Filter.
@@ -155,14 +185,13 @@ public class ProxyFilter {
155185 ///
156186 /// The value is set in the ``MeshNetworkManager`` initializer.
157187 private let delegateQueue : DispatchQueue
158- /// The counter is used to prevent from refreshing the filter in a loop when the Proxy Server
159- /// responds with an unexpected list size.
160- private var counter = 0
161188 /// The flag is set to `true` when a request has been sent to the connected proxy.
162189 /// It is cleared when a response was received, or in case of an error.
163190 private var busy = false
164191 /// A queue of proxy configuration messages enqueued to be sent.
165192 private var buffer : [ ProxyConfigurationMessage ] = [ ]
193+ /// The last Proxy Configuration message sent.
194+ private var request : ProxyConfigurationMessage ?
166195 /// A shortcut to the manager's logger.
167196 private var logger : LoggerDelegate ? {
168197 return manager? . logger
@@ -315,6 +344,13 @@ public extension ProxyFilter {
315344 /// This method will unset the `busy` flag.
316345 func proxyDidDisconnect( ) {
317346 newNetworkCreated ( )
347+
348+ // Notify the delegate.
349+ delegateQueue. async { [ delegate] in
350+ delegate? . proxyFilterUpdated ( type: . acceptList, addresses: [ ] )
351+ // For backwards compatibility, call the deprecated method.
352+ delegate? . proxyFilterUpdateAcknowledged ( type: . acceptList, listSize: 0 )
353+ }
318354 }
319355
320356}
@@ -382,8 +418,8 @@ extension ProxyFilter: ProxyFilterEventHandler {
382418 addresses. removeAll ( )
383419 buffer. removeAll ( )
384420 busy = false
385- counter = 0
386421 proxy = nil
422+ request = nil
387423 }
388424 }
389425
@@ -409,38 +445,16 @@ extension ProxyFilter: ProxyFilterEventHandler {
409445
410446 func managerDidDeliverMessage( _ message: ProxyConfigurationMessage ) {
411447 mutex. sync {
412- switch message {
413- case let request as AddAddressesToFilter :
414- addresses. formUnion ( request. addresses)
415- case let request as RemoveAddressesFromFilter :
416- addresses. subtract ( request. addresses)
417- case let request as SetFilterType :
418- type = request. filterType
419- addresses. removeAll ( )
420- default :
421- // Ignore.
422- break
423- }
424- }
425- // And notify the app.
426- delegateQueue. async {
427- self . delegate? . proxyFilterUpdated ( type: self . type, addresses: self . addresses)
448+ request = message
428449 }
429450 }
430451
431452 func managerFailedToDeliverMessage( _ message: ProxyConfigurationMessage , error: Error ) {
432453 mutex. sync {
433- type = . acceptList
434- addresses. removeAll ( )
435- buffer. removeAll ( )
436454 busy = false
437455 }
438456 if case BearerError . bearerClosed = error {
439- proxy = nil
440- }
441- // And notify the app.
442- delegateQueue. async {
443- self . delegate? . proxyFilterUpdated ( type: self . type, addresses: self . addresses)
457+ proxyDidDisconnect ( )
444458 }
445459 }
446460
@@ -449,60 +463,75 @@ extension ProxyFilter: ProxyFilterEventHandler {
449463
450464 switch message {
451465 case let status as FilterStatus :
452- self . proxy = proxy
466+ var expectedListSize : Int = addresses. count
467+ mutex. sync {
468+ self . proxy = proxy
469+
470+ // Based on the request for which status was received, and the status
471+ // itself, calculate the final list of addresses.
472+ if let request = request {
473+ switch request {
474+ // Addresses were sent in ascending order (primary unicast address first).
475+ // On every device there's an upper limit of the size of Proxy Filter List.
476+ // Assuming that devices are added in the order they were sent (as they should),
477+ // we must cut above the limit.
478+ case let request as AddAddressesToFilter :
479+ expectedListSize = addresses. count + request. addresses. count
480+ let addedAddresses = request. addresses. sorted ( ) . prefix ( Int ( status. listSize) - addresses. count)
481+ addresses. formUnion ( addedAddresses)
482+
483+ // Removing is easy. We always remove all requested.
484+ case let request as RemoveAddressesFromFilter :
485+ addresses. subtract ( request. addresses)
486+ expectedListSize = addresses. count
487+
488+ // Setting the filter always resets the list.
489+ case let request as SetFilterType :
490+ type = request. filterType
491+ addresses. removeAll ( )
492+ expectedListSize = 0
493+
494+ // Other values are not possible.
495+ default : break
496+ }
497+ self . request = nil
498+ }
499+ }
500+
453501 // Handle buffered messages.
454502 if let nextMessage = mutex. sync ( execute: {
455503 buffer. isEmpty ? nil : buffer. removeFirst ( )
456504 } ) {
457- try ? manager. send ( nextMessage)
458- return
505+ // Add more addresses only when we're below the limit.
506+ if expectedListSize == addresses. count {
507+ try ? manager. send ( nextMessage)
508+ return
509+ } else {
510+ mutex. sync {
511+ buffer. removeAll ( )
512+ }
513+ }
459514 }
460515 mutex. sync {
461516 busy = false
462517 }
518+ // Notify the delegate.
519+ delegateQueue. async { [ delegate] in
520+ delegate? . proxyFilterUpdated ( type: self . type, addresses: self . addresses)
521+ }
463522
464523 // Ensure the current information about the filter is up to date.
465- guard type == status. filterType && addresses. count == status. listSize else {
466- // The counter is used to prevent from refreshing the
467- // filter in a loop when the Proxy Server responds with
468- // an unexpected list size.
469- guard counter == 0 else {
470- logger? . e ( . proxy, " Proxy Filter lost track of devices " )
471- counter = 0
472- return
473- }
474- counter += 1
475-
476- // Some devices support just a single address in Proxy Filter.
477- // After adding 2+ devices they will reply with list size = 1.
478- // In that case we could either switch to exclusion list type of filter
479- // to get all the traffic, or add only 1 address. By default, this
480- // library will add the 0th Element's Unicast Address to allow
481- // configuration, as this is the most common use case. If you need
482- // to receive messages sent to group addresses or other Elements,
483- // switch to exclusion list filter.
484- if status. listSize == 1 {
485- logger? . w ( . proxy, " Limited Proxy Filter detected. " )
486- reset ( )
487- if let address = manager. meshNetwork? . localProvisioner? . primaryUnicastAddress {
488- mutex. sync {
489- addresses = [ address]
490- }
491- add ( addresses: addresses)
492- }
493- delegateQueue. async {
494- self . delegate? . limitedProxyFilterDetected ( maxSize: 1 )
495- }
496- } else {
497- logger? . w ( . proxy, " Refreshing Proxy Filter... " )
498- let addresses = self . addresses // reset() will erase addresses, store it.
499- reset ( )
500- add ( addresses: addresses)
524+ guard type == status. filterType && expectedListSize == status. listSize else {
525+ logger? . w ( . proxy, " Proxy Filter limit reached: \( status. listSize) (expected: \( expectedListSize) ) " )
526+ delegateQueue. async { [ delegate] in
527+ delegate? . proxyFilterLimitReached ( type: self . type, maxSize: status. listSize)
528+ // For backwards compatibility, call the old method.
529+ delegate? . limitedProxyFilterDetected ( maxSize: Int ( status. listSize) )
501530 }
502531 return
503532 }
504- counter = 0
505533 delegateQueue. async { [ delegate] in
534+ // For backwards compatibility, call the deprecated method.
506535 delegate? . proxyFilterUpdateAcknowledged ( type: status. filterType, listSize: status. listSize)
507536 }
508537 default :
0 commit comments