novotnyllc / Zeroconf

Bonjour support for .NET Core, .NET 4.6, Xamarin, and UWP
MIT License
367 stars 92 forks source link

Null Exception on iOS #261

Open addibouk opened 1 year ago

addibouk commented 1 year ago

When using Zeroconf on iOS I am receiving the following exception when it discovers my network service...

2023-08-25 20:37:50.548 Xamarin.PreBuilt.iOS[29787:2069182] OnError: System.ArgumentNullException: Value cannot be null.
Parameter name: key
  at System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) [0x00008] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs:488 
  at System.Collections.Generic.Dictionary`2[TKey,TValue].set_Item (TKey key, TValue value) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs:231 
  at Zeroconf.ZeroconfHost.AddService (Zeroconf.IService service) [0x00000] in /_/Zeroconf/ZeroconfRecord.cs:193 
  at Zeroconf.BonjourBrowser.RefreshZeroconfHostDict () [0x00121] in /_/Zeroconf/BonjourBrowser.cs:436 
  at Zeroconf.BonjourBrowser.ReturnZeroconfHostResults () [0x00028] in /_/Zeroconf/BonjourBrowser.cs:361 
  at Zeroconf.ZeroconfNetServiceBrowser.ResolveAsync (Zeroconf.ResolveOptions options, System.Action`1[T] callback, System.Threading.CancellationToken cancellationToken, System.Net.NetworkInformation.NetworkInterface[] netInterfacesToSendRequestOn) [0x0010b] in /_/Zeroconf/ZeroconfNetServiceBrowser.cs:39 
  at Zeroconf.ZeroconfResolver.ResolveAsync (Zeroconf.ResolveOptions options, System.Action`1[T] callback, System.Threading.CancellationToken cancellationToken, System.Net.NetworkInformation.NetworkInterface[] netInterfacesToSendRequestOn) [0x000e0] in /_/Zeroconf/ZeroconfResolver.Async.cs:105 
  at Zeroconf.ZeroconfResolver+<>c__DisplayClass27_0.<Resolve>b__0 (System.IObserver`1[T] obs, System.Threading.CancellationToken cxl) [0x00040] in /_/Zeroconf/ZeroconfResolver.Observable.cs:75

Any ideas?

elementalpete commented 9 months ago

I am running into the same issue. After looking into it further, it looks like when the ZeroconfHost is created in BonjourBrowser.cs (which only runs on iOS), the ServiceName is not set like it is in the equivalent non-iOS code. I am looking at the RefreshZeroconfHostDict() method, which currently starts on line 375. Starting on line 399, I see the following:

Service svc = new Service();
svc.Name = GetNsNetServiceName(nsNetService);
svc.Port = (int)nsNetService.Port;
// svc.Ttl = is not available

// DS: We need to set svc.ServiceName or we get a NullReferenceException
// Name is the name retrieved from the PTR record, e.g. _http._tcp.local.
// ServiceName is the name retrieved from the SRV record e.g. myserver._http._tcp.local.
// I'm not sure if this fix works across the board, e.g. when two devices of the same model exist on the same network
svc.ServiceName = $"{nsNetService.Name}{nsNetService.Type}{nsNetService.Domain}";

The fix that I added causes the code to succeed in my home, but I am not sure if it is a "full fix" - when more than one device in the network tries to use the same ServiceName, the service provider is supposed to append a number to the end in a headless application, or prompt the user for a new name in a UI-based application, to avoid naming conflicts. This is reflected in the SRV record. I'm not familiar enough with this code to know if my fix addresses this situation, nor do I currently have a way of testing. Hopefully this will help someone, though.