[Network] Fix a few issues with the callbacks in NWPath. Fixes #13772. (#16138)

* Change EnumerateGateways to use the 'static_EnumerateGatewaysHandler'
  callback. It looks like this was a c&p error, since the
  'static_EnumerateGatewaysHandler' callback was implemented, just never
  referenced anywhere.
* Add an overload to EnumerateGateways and EnumerateInterfaces that takes a
  callback that returns a bool indicating whether the enumeration should
  continue. This mirrors the native API.
* Obsolete the EnumerateGateways and EnumerateInterfaces overloads that take a
  void callback (and remove in XAMCORE_5_0).
* Add a test for EnumerateGateways that works (the previous failed, but never
  asserted the failure, so it would just silently time out).

Fixes https://github.com/xamarin/xamarin-macios/issues/13772.
This commit is contained in:
Rolf Bjarne Kvinge 2022-10-03 12:11:52 +02:00 коммит произвёл GitHub
Родитель 513355602d
Коммит 7e6edcbc36
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 91 добавлений и 20 удалений

Просмотреть файл

@ -10,6 +10,7 @@
#nullable enable
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using ObjCRuntime;
@ -112,22 +113,42 @@ namespace Network {
return nw_path_is_equal (GetCheckedHandle (), other.Handle);
}
delegate void nw_path_enumerate_interfaces_block_t (IntPtr block, IntPtr iface);
// Returning 'byte' since 'bool' isn't blittable
delegate byte nw_path_enumerate_interfaces_block_t (IntPtr block, IntPtr iface);
static nw_path_enumerate_interfaces_block_t static_Enumerator = TrampolineEnumerator;
[MonoPInvokeCallback (typeof (nw_path_enumerate_interfaces_block_t))]
static void TrampolineEnumerator (IntPtr block, IntPtr iface)
static byte TrampolineEnumerator (IntPtr block, IntPtr iface)
{
var del = BlockLiteral.GetTarget<Action<NWInterface>> (block);
var del = BlockLiteral.GetTarget<Func<NWInterface, bool>> (block);
if (del is not null)
del (new NWInterface (iface, owns: false));
return del (new NWInterface (iface, owns: false)) ? (byte) 1 : (byte) 0;
return 0;
}
[DllImport (Constants.NetworkLibrary)]
static extern void nw_path_enumerate_interfaces (IntPtr handle, ref BlockLiteral callback);
[BindingImpl (BindingImplOptions.Optimizable)]
#if !XAMCORE_5_0
[Obsolete ("Use the overload that takes a 'Func<NWInterface, bool>' instead.")]
[EditorBrowsable (EditorBrowsableState.Never)]
public void EnumerateInterfaces (Action<NWInterface> callback)
{
if (callback is null)
return;
Func<NWInterface, bool> func = (v) =>
{
callback (v);
return true;
};
EnumerateInterfaces (func);
}
#endif // !XAMCORE_5_0
[BindingImpl (BindingImplOptions.Optimizable)]
public void EnumerateInterfaces (Func<NWInterface, bool> callback)
{
if (callback is null)
return;
@ -181,19 +202,45 @@ namespace Network {
[DllImport (Constants.NetworkLibrary)]
static extern void nw_path_enumerate_gateways (IntPtr path, ref BlockLiteral enumerate_block);
delegate void nw_path_enumerate_gateways_t (IntPtr block, IntPtr endpoint);
// Returning 'byte' since 'bool' isn't blittable
delegate byte nw_path_enumerate_gateways_t (IntPtr block, IntPtr endpoint);
static nw_path_enumerate_gateways_t static_EnumerateGatewaysHandler = TrampolineGatewaysHandler;
[MonoPInvokeCallback (typeof (nw_path_enumerate_gateways_t))]
static void TrampolineGatewaysHandler (IntPtr block, IntPtr endpoint)
static byte TrampolineGatewaysHandler (IntPtr block, IntPtr endpoint)
{
var del = BlockLiteral.GetTarget<Action<NWEndpoint>> (block);
var del = BlockLiteral.GetTarget<Func<NWEndpoint, bool>> (block);
if (del is not null) {
var nwEndpoint = new NWEndpoint (endpoint, owns: false);
del (nwEndpoint);
return del (nwEndpoint) ? (byte) 1 : (byte) 0;
}
return 0;
}
#if !XAMCORE_5_0
#if NET
[SupportedOSPlatform ("tvos13.0")]
[SupportedOSPlatform ("macos10.15")]
[SupportedOSPlatform ("ios13.0")]
[SupportedOSPlatform ("maccatalyst")]
#else
[TV (13,0)]
[Mac (10,15)]
[iOS (13,0)]
#endif
[Obsolete ("Use the overload that takes a 'Func<NWEndpoint, bool>' instead.")]
[EditorBrowsable (EditorBrowsableState.Never)]
public void EnumerateGateways (Action<NWEndpoint> callback)
{
Func<NWEndpoint,bool> func = (v) =>
{
callback (v);
return true;
};
EnumerateGateways (func);
}
#endif
#if NET
[SupportedOSPlatform ("tvos13.0")]
[SupportedOSPlatform ("macos10.15")]
@ -205,13 +252,13 @@ namespace Network {
[iOS (13,0)]
#endif
[BindingImpl (BindingImplOptions.Optimizable)]
public void EnumerateGateways (Action<NWEndpoint> callback)
public void EnumerateGateways (Func<NWEndpoint, bool> callback)
{
if (callback is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback));
BlockLiteral block_handler = new BlockLiteral ();
block_handler.SetupBlockUnsafe (static_Enumerator, callback);
block_handler.SetupBlockUnsafe (static_EnumerateGatewaysHandler, callback);
try {
nw_path_enumerate_gateways (GetCheckedHandle (), ref block_handler);

Просмотреть файл

@ -43,7 +43,7 @@ namespace Cecil.Tests {
}
// TODO: Events?
Assert.That (found, Is.Empty, "Obsolete API");
Assert.That (found, Is.Empty, "Obsolete API: add '[EditorBrowsable (EditorBrowsableState.Never)]' for newly obsoleted API to pass this test.");
}
bool FilterMember (ICustomAttributeProvider provider)

Просмотреть файл

@ -162,19 +162,43 @@ namespace MonoTouchFixtures.Network {
{
TestRuntime.AssertXcodeVersion (11, 0);
Assert.Throws<ArgumentNullException> (() => { path.EnumerateGateways (null); });
Assert.Throws<ArgumentNullException> (() => { path.EnumerateGateways ((Func<NWEndpoint, bool>) null); });
}
[Test]
public void EnumerateGatewayTest ()
{
TestRuntime.AssertXcodeVersion (11, 0);
var e = new AutoResetEvent (false);
path.EnumerateGateways ((endPoint) => {
Assert.IsNotNull (endPoint);
e.Set ();
});
e.WaitOne (10000);
var e1 = new ManualResetEvent (false);
var e2 = new ManualResetEvent (false);
var monitor = new NWPathMonitor ();
try {
monitor.SetQueue (DispatchQueue.DefaultGlobalQueue);
monitor.Start ();
monitor.SnapshotHandler += path =>
{
path.EnumerateGateways (gateway =>
{
e1.Set ();
return true;
});
path.EnumerateInterfaces (@interface =>
{
e2.Set ();
return true;
});
};
TestRuntime.RunAsync (TimeSpan.FromSeconds (5),
() => { },
() => WaitHandle.WaitAll (new WaitHandle [] { e1, e2 }, 0));
var rv = WaitHandle.WaitAll (new WaitHandle [] { e1, e2 }, 10000);
if (!rv)
TestRuntime.IgnoreInCI ("This test doesn't seem to be working on the bots, uncommon network setup?");
Assert.IsTrue (rv, "Called back");
} finally {
monitor.Cancel ();
monitor.Dispose ();
}
}
[Test]