Skip to content

Commit 0dbbbef

Browse files
committed
Bugfix: Proxy tab not showing reaching list size limit
1 parent c2803a1 commit 0dbbbef

4 files changed

Lines changed: 163 additions & 86 deletions

File tree

Example/Source/View Controllers/Proxy/AddAddressViewController.swift

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,33 @@ private extension AddAddressViewController {
195195
extension AddAddressViewController: ProxyFilterDelegate {
196196

197197
func proxyFilterUpdated(type: ProxyFilerType, addresses: Set<Address>) {
198-
done {
199-
self.dismiss(animated: true)
200-
}
198+
// As we want different behavior when the list was acknowledged
199+
// or the list limit was reached, to nothing here.
201200
}
202201

203202
func proxyFilterUpdateAcknowledged(type: ProxyFilerType, listSize: UInt16) {
204-
// TODO: dismiss here?
203+
// This method is also called when the Proxy Node gets disconnected.
204+
// In that case, the list size is equal to 0.
205+
if listSize > 0 {
206+
done {
207+
self.dismiss(animated: true)
208+
}
209+
}
210+
}
211+
212+
func proxyFilterLimitReached(type: ProxyFilerType, maxSize: UInt16) {
213+
done {
214+
self.presentAlert(
215+
title: "Maximum filter size reached",
216+
message: """
217+
The connected proxy node supports only \(maxSize) addresses on its Proxy Filter list.
218+
219+
Some addresses were not added.
220+
"""
221+
) { _ in
222+
self.dismiss(animated: true)
223+
}
224+
}
205225
}
206226

207227
}

Example/Source/View Controllers/Proxy/ProxySelectorViewController.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,20 @@ extension ProxySelectorViewController: GattBearerDelegate {
188188

189189
func bearerDidOpen(_ bearer: Bearer) {
190190
MeshNetworkManager.bearer.use(proxy: bearer as! GattBearer)
191-
if let provisioner = meshNetwork?.localProvisioner {
192-
MeshNetworkManager.instance.proxyFilter.proxyDidDisconnect()
193-
MeshNetworkManager.instance.proxyFilter.setup(for: provisioner)
194-
}
191+
MeshNetworkManager.instance.proxyFilter.proxyDidDisconnect()
192+
195193
DispatchQueue.main.async { [weak self] in
196194
self?.alert?.dismiss(animated: true) { [weak self] in
197-
self?.dismiss(animated: true)
195+
self?.dismiss(animated: true) {
196+
// Set up the Proxy Filter when the view controller is no
197+
// longer visible. This action may end up reaching the Proxy
198+
// Filter list limit, which will result in showing an alert
199+
// from the ProxyViewController. Having 2 child view controllers
200+
// won't work.
201+
if let provisioner = self?.meshNetwork?.localProvisioner {
202+
MeshNetworkManager.instance.proxyFilter.setup(for: provisioner)
203+
}
204+
}
198205
}
199206
self?.alert = nil
200207
}

Example/Source/View Controllers/Proxy/ProxyViewController.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,36 @@ extension ProxyViewController: ProxyFilterTypeDelegate {
222222
extension ProxyViewController: ProxyFilterDelegate {
223223

224224
func proxyFilterUpdated(type: ProxyFilerType, addresses: Set<Address>) {
225+
// As we want different behavior when the list was acknowledged
226+
// or the list limit was reached, to nothing here.
227+
}
228+
229+
func proxyFilterUpdateAcknowledged(type: ProxyFilerType, listSize: UInt16) {
230+
// This method is also called when the Proxy Node gets disconnected.
231+
// In that case, the list size is equal to 0.
225232
done {
226233
self.tableView.reloadData()
227234
}
228235
}
229236

230-
func proxyFilterUpdateAcknowledged(type: ProxyFilerType, listSize: UInt16) {
231-
// TODO: dismiss here?
237+
func proxyFilterLimitReached(type: ProxyFilerType, maxSize: UInt16) {
238+
done {
239+
self.tableView.reloadData()
240+
let setRejectList = UIAlertAction(title: "Use Reject List", style: .destructive) { _ in
241+
let proxyFilter = MeshNetworkManager.instance.proxyFilter
242+
proxyFilter.setType(.rejectList)
243+
}
244+
self.presentAlert(
245+
title: "Maximum filter size reached",
246+
message: """
247+
The connected proxy node supports only \(maxSize) addresses on its Proxy Filter list.
248+
249+
Use Reject List or add addresses manually.
250+
""",
251+
option: setRejectList
252+
)
253+
}
232254
}
233-
234255
}
235256

236257
private extension ProxyViewController {

nRFMeshProvision/ProxyFilter.swift

Lines changed: 103 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -70,26 +70,48 @@ public enum ProxyFilerType {
7070
public 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

Comments
 (0)