public static CFProxy[] ExecuteProxyAutoConfigurationUrl(Uri proxyAutoConfigurationUrl, Uri targetUrl, out NSError outError) { outError = null; if (proxyAutoConfigurationUrl == null) { throw new ArgumentNullException(nameof(proxyAutoConfigurationUrl)); } if (targetUrl == null) { throw new ArgumentNullException(nameof(targetUrl)); } using (var pacUrl = new NSUrl(proxyAutoConfigurationUrl.AbsoluteUri)) // toll free bridge to CFUrl using (var url = new NSUrl(targetUrl.AbsoluteUri)) { CreatePACCFRunLoopSource factory = delegate(CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return(CFNetworkExecuteProxyAutoConfigurationURL(pacUrl.Handle, url.Handle, cb, ref context)); }; return(ExecutePacCFRunLoopSourceBlocking(factory, out outError)); } }
public static async Task <(CFProxy[] proxies, NSError error)> ExecuteProxyAutoConfigurationScriptAsync(string proxyAutoConfigurationScript, Uri targetUrl, CancellationToken cancellationToken) { if (proxyAutoConfigurationScript == null) { throw new ArgumentNullException(nameof(proxyAutoConfigurationScript)); } if (targetUrl == null) { throw new ArgumentNullException(nameof(targetUrl)); } using (var pacScript = new NSString(proxyAutoConfigurationScript)) using (var url = new NSUrl(targetUrl.AbsoluteUri)) { CreatePACCFRunLoopSource factory = delegate(CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return(CFNetworkExecuteProxyAutoConfigurationScript(pacScript.Handle, url.Handle, cb, ref context)); }; // use the helper task with a factory for this method return(await ExecutePacCFRunLoopSourceAsync(factory, cancellationToken).ConfigureAwait(false)); } }
static CFProxy[] ExecutePacCFRunLoopSourceBlocking(CreatePACCFRunLoopSource factory, out NSError outError) { var runLoop = CFRunLoop.Current; outError = null; // build a struct that will have all the needed info for the callback var pacCbData = new PACProxyCallbackData(); pacCbData.CFRunLoopPtr = runLoop.Handle; var pacDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pacCbData)); try { Marshal.StructureToPtr(pacCbData, pacDataPtr, false); var clientContext = new CFStreamClientContext(); clientContext.Info = pacDataPtr; using (var loopSource = new CFRunLoopSource(factory(ExecutePacCallback, ref clientContext))) using (var mode = new NSString("Xamarin.iOS.Proxy")) { runLoop.AddSource(loopSource, mode); runLoop.RunInMode(mode, double.MaxValue, false); runLoop.RemoveSource(loopSource, mode); } pacCbData = (PACProxyCallbackData)Marshal.PtrToStructure(pacDataPtr, typeof(PACProxyCallbackData)); // get data from the struct outError = pacCbData.Error; return(pacCbData.ProxyList); } finally { if (pacCbData.ProxyListPtr != IntPtr.Zero) { CFObject.CFRelease(pacCbData.ProxyListPtr); } if (pacCbData.ErrorPtr != IntPtr.Zero) { NSObject.DangerousRelease(pacCbData.ErrorPtr); } Marshal.FreeHGlobal(pacDataPtr); } }
public static async Task <(CFProxy[] proxies, NSError error)> ExecuteProxyAutoConfigurationUrlAsync(Uri proxyAutoConfigurationUrl, Uri targetUrl, CancellationToken cancellationToken) { // similar to the sync method, but we will spawn a thread and wait in an async manner to an autoreset event to be fired if (proxyAutoConfigurationUrl == null) { throw new ArgumentNullException(nameof(proxyAutoConfigurationUrl)); } if (targetUrl == null) { throw new ArgumentNullException(nameof(targetUrl)); } using (var pacUrl = new NSUrl(proxyAutoConfigurationUrl.AbsoluteUri)) // toll free bridge to CFUrl using (var url = new NSUrl(targetUrl.AbsoluteUri)) { CreatePACCFRunLoopSource factory = delegate(CFProxyAutoConfigurationResultCallbackInternal cb, ref CFStreamClientContext context) { return(CFNetworkExecuteProxyAutoConfigurationURL(pacUrl.Handle, url.Handle, cb, ref context)); }; // use the helper task with a factory for this method return(await ExecutePacCFRunLoopSourceAsync(factory, cancellationToken).ConfigureAwait(false)); } }
static async Task <(CFProxy[] proxies, NSError error)> ExecutePacCFRunLoopSourceAsync(CreatePACCFRunLoopSource factory, CancellationToken cancellationToken) { CFProxy[] proxies = null; NSError outError = null; if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException("Operation was cancelled."); } await Task.Run(() => { // we need the runloop of THIS thread, so it is important to get it in the correct context var runLoop = CFRunLoop.Current; // build a struct that will have all the needed info for the callback var pacCbData = new PACProxyCallbackData(); pacCbData.CFRunLoopPtr = runLoop.Handle; var pacDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pacCbData)); try { Marshal.StructureToPtr(pacCbData, pacDataPtr, false); var clientContext = new CFStreamClientContext(); clientContext.Info = pacDataPtr; using (var loopSource = new CFRunLoopSource(factory(ExecutePacCallback, ref clientContext))) using (var mode = new NSString("Xamarin.iOS.Proxy")) { if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException("Operation was cancelled."); } cancellationToken.Register(() => { //if user cancels, we invalidte the source, stop the runloop and remove the source loopSource.Invalidate(); runLoop.RemoveSource(loopSource, mode); runLoop.Stop(); }); runLoop.AddSource(loopSource, mode); // blocks until stop is called, will be done in the cb set previously runLoop.RunInMode(mode, double.MaxValue, false); // does not raise an error if source is not longer present, so no need to worry runLoop.RemoveSource(loopSource, mode); } if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException("Operation was cancelled."); } pacCbData = (PACProxyCallbackData)Marshal.PtrToStructure(pacDataPtr, typeof(PACProxyCallbackData)); // get data from the struct proxies = pacCbData.ProxyList; outError = pacCbData.Error; } finally { // clean resources if (pacCbData.ProxyListPtr != IntPtr.Zero) { CFObject.CFRelease(pacCbData.ProxyListPtr); } if (pacCbData.ErrorPtr != IntPtr.Zero) { NSObject.DangerousRelease(pacCbData.ErrorPtr); } Marshal.FreeHGlobal(pacDataPtr); } }, cancellationToken).ConfigureAwait(false); if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException("Operation was cancelled."); } return(proxies : proxies, error : outError); }