public void EnableEvents(CFRunLoop runLoop, NSString runLoopMode) { if (open || closed || (loop != null)) { throw new InvalidOperationException(); } CheckHandle(); loop = runLoop; loopMode = runLoopMode; var ctx = new CFStreamClientContext(); ctx.Info = GCHandle.ToIntPtr(gch); var args = CFStreamEventType.OpenCompleted | CFStreamEventType.CanAcceptBytes | CFStreamEventType.HasBytesAvailable | CFStreamEventType.CanAcceptBytes | CFStreamEventType.ErrorOccurred | CFStreamEventType.EndEncountered; var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CFStreamClientContext))); try { Marshal.StructureToPtr(ctx, ptr, false); if (!DoSetClient(OnCallback, (nint)(long)args, ptr)) { throw new InvalidOperationException("Stream does not support async events."); } } finally { Marshal.FreeHGlobal(ptr); } ScheduleWithRunLoop(runLoop, runLoopMode); }
internal CFSocket(CFSocketNativeHandle sock) { var cbTypes = CFSocketCallBackType.DataCallBack | CFSocketCallBackType.WriteCallBack; gch = GCHandle.Alloc(this); var ctx = new CFStreamClientContext(); ctx.Info = GCHandle.ToIntPtr(gch); var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CFStreamClientContext))); try { Marshal.StructureToPtr(ctx, ptr, false); handle = CFSocketCreateWithNative( IntPtr.Zero, sock, (nuint)(ulong)cbTypes, OnCallback, ptr); } finally { Marshal.FreeHGlobal(ptr); } if (handle == IntPtr.Zero) { throw new CFSocketException(CFSocketError.Error); } var source = new CFRunLoopSource(CFSocketCreateRunLoopSource(IntPtr.Zero, handle, 0)); var loop = CFRunLoop.Current; loop.AddSource(source, CFRunLoop.ModeDefault); }
CFSocket(int family, int type, int proto, CFRunLoop loop) { var cbTypes = CFSocketCallBackType.DataCallBack | CFSocketCallBackType.ConnectCallBack; gch = GCHandle.Alloc(this); var ctx = new CFStreamClientContext(); ctx.Info = GCHandle.ToIntPtr(gch); var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CFStreamClientContext))); try { Marshal.StructureToPtr(ctx, ptr, false); handle = CFSocketCreate( IntPtr.Zero, family, type, proto, (nuint)(ulong)cbTypes, OnCallback, ptr); } finally { Marshal.FreeHGlobal(ptr); } if (handle == IntPtr.Zero) { throw new CFSocketException(CFSocketError.Error); } gch = GCHandle.Alloc(this); var source = new CFRunLoopSource(CFSocketCreateRunLoopSource(IntPtr.Zero, handle, 0)); loop.AddSource(source, CFRunLoop.ModeDefault); }
CFSocket(int family, int type, int proto, CFRunLoop loop) { var cbTypes = CFSocketCallBackType.DataCallBack | CFSocketCallBackType.ConnectCallBack; gch = GCHandle.Alloc(this); try { var ctx = new CFStreamClientContext(); ctx.Info = GCHandle.ToIntPtr(gch); var handle = CFSocketCreate(IntPtr.Zero, family, type, proto, (nuint)(ulong)cbTypes, OnCallback, ref ctx); InitializeHandle(handle); var source = new CFRunLoopSource(CFSocketCreateRunLoopSource(IntPtr.Zero, handle, 0), true); loop.AddSource(source, CFRunLoop.ModeDefault); } catch { gch.Free(); throw; } }
CFSocket(CFSocketNativeHandle sock) { var cbTypes = CFSocketCallBackType.DataCallBack | CFSocketCallBackType.WriteCallBack; gch = GCHandle.Alloc(this); try { var ctx = new CFStreamClientContext(); ctx.Info = GCHandle.ToIntPtr(gch); var handle = CFSocketCreateWithNative(IntPtr.Zero, sock, (nuint)(ulong)cbTypes, OnCallback, ref ctx); InitializeHandle(handle); var source = new CFRunLoopSource(CFSocketCreateRunLoopSource(IntPtr.Zero, handle, 0), true); var loop = CFRunLoop.Current; loop.AddSource(source, CFRunLoop.ModeDefault); } catch { gch.Free(); throw; } }
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); } }
extern static IntPtr CFSocketCreateWithNative(IntPtr allocator, CFSocketNativeHandle sock, nuint /*CFOptionFlags*/ callBackTypes, CFSocketCallBack callout, ref CFStreamClientContext ctx);
extern static IntPtr CFSocketCreate(IntPtr allocator, int /*SInt32*/ family, int /*SInt32*/ type, int /*SInt32*/ proto, nuint /*CFOptionFlags*/ callBackTypes, CFSocketCallBack callout, ref CFStreamClientContext ctx);
extern static /* CFRunLoopSourceRef __nonnull */ IntPtr CFNetworkExecuteProxyAutoConfigurationURL( /* CFURLRef __nonnull */ IntPtr proxyAutoConfigurationURL, /* CFURLRef __nonnull */ IntPtr targetURL, /* CFProxyAutoConfigurationResultCallback __nonnull */ CFProxyAutoConfigurationResultCallbackInternal cb, /* CFStreamClientContext * __nonnull */ ref CFStreamClientContext clientContext);
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); }
public static CFRunLoopSource ExecuteProxyAutoConfigurationURL(NSUrl proxyAutoConfigurationURL, NSUrl targetURL, CFProxyAutoConfigurationResultCallback resultCallback, CFStreamClientContext clientContext) { if (proxyAutoConfigurationURL == null) { throw new ArgumentNullException("proxyAutoConfigurationURL"); } if (targetURL == null) { throw new ArgumentNullException("targetURL"); } if (resultCallback == null) { throw new ArgumentNullException("resultCallback"); } if (clientContext == null) { throw new ArgumentNullException("clientContext"); } IntPtr source = CFNetworkExecuteProxyAutoConfigurationURL(proxyAutoConfigurationURL.Handle, targetURL.Handle, resultCallback, clientContext); return((source == IntPtr.Zero) ? null : new CFRunLoopSource(source)); }