示例#1
0
        private unsafe IPEndPoint Start(QuicListenerOptions options)
        {
            List <SslApplicationProtocol> applicationProtocols = options.ServerAuthenticationOptions !.ApplicationProtocols !;
            IPEndPoint listenEndPoint = options.ListenEndPoint !;

            Internals.SocketAddress address = IPEndPointExtensions.Serialize(listenEndPoint);

            Debug.Assert(_stateHandle.IsAllocated);
            try
            {
                Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
                using var msquicBuffers = new MsQuicBuffers();
                msquicBuffers.Initialize(applicationProtocols, applicationProtocol => applicationProtocol.Protocol);
                // TODO: is the layout same for SocketAddress.Buffer and QuicAddr?
                // TODO: maybe add simple extensions/helpers:
                //       - QuicAddr ToQuicAddr(this IPEndPoint ipEndPoint)
                //       - IPEndPoint ToIPEndPoint(this ref QuicAddr quicAddress)
                fixed(byte *paddress = address.Buffer)
                {
                    ThrowIfFailure(MsQuicApi.Api.ApiTable->ListenerStart(
                                       _state.Handle.QuicHandle,
                                       msquicBuffers.Buffers,
                                       (uint)applicationProtocols.Count,
                                       (QuicAddr *)paddress), "ListenerStart failed");
                }
            }
            catch
            {
                _stateHandle.Free();
                throw;
            }

            Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
            return(MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LISTENER_LOCAL_ADDRESS));
        }
示例#2
0
        internal static unsafe QuicAddr ToQuicAddr(this IPEndPoint iPEndPoint)
        {
            // TODO: is the layout same for SocketAddress.Buffer and QuicAddr on all platforms?
            QuicAddr    result     = default;
            Span <byte> rawAddress = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref result, 1));

            Internals.SocketAddress address = IPEndPointExtensions.Serialize(iPEndPoint);
            Debug.Assert(address.Size <= rawAddress.Length);

            address.Buffer.AsSpan(0, address.Size).CopyTo(rawAddress);
            return(result);
        }
        internal static unsafe void SetIPEndPointParam(MsQuicApi api, SafeHandle nativeObject, uint param, IPEndPoint value)
        {
            Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(value);

            // MsQuic always reads same amount of memory as if IPv6 was used, so we can't pass pointer to socketAddress.Buffer directly
            Span <byte> address = stackalloc byte[Internals.SocketAddress.IPv6AddressSize];

            socketAddress.Buffer.AsSpan(0, socketAddress.Size).CopyTo(address);
            address.Slice(socketAddress.Size).Clear();

            fixed(byte *paddress = &MemoryMarshal.GetReference(address))
            {
                QuicExceptionHelpers.ThrowIfFailed(
                    api.SetParamDelegate(nativeObject, param, (uint)address.Length, paddress),
                    "Could not set IPEndPoint");
            }
        }
示例#4
0
        private int SendEcho(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool isAsync)
        {
            Interop.IpHlpApi.IPOptions ipOptions = new Interop.IpHlpApi.IPOptions(options);
            if (!_ipv6)
            {
                return((int)Interop.IpHlpApi.IcmpSendEcho2(
                           _handlePingV4,
                           GetWaitHandle(isAsync),
                           IntPtr.Zero,
                           IntPtr.Zero,
#pragma warning disable CS0618 // Address is marked obsolete
                           (uint)address.Address,
#pragma warning restore CS0618
                           _requestBuffer,
                           (ushort)buffer.Length,
                           ref ipOptions,
                           _replyBuffer,
                           MaxUdpPacket,
                           (uint)timeout));
            }

            IPEndPoint ep = new IPEndPoint(address, 0);
            Internals.SocketAddress remoteAddr = IPEndPointExtensions.Serialize(ep);
            byte[] sourceAddr = new byte[28];

            return((int)Interop.IpHlpApi.Icmp6SendEcho2(
                       _handlePingV6,
                       GetWaitHandle(isAsync),
                       IntPtr.Zero,
                       IntPtr.Zero,
                       sourceAddr,
                       remoteAddr.Buffer,
                       _requestBuffer,
                       (ushort)buffer.Length,
                       ref ipOptions,
                       _replyBuffer,
                       MaxUdpPacket,
                       (uint)timeout));
        }
示例#5
0
        private unsafe IPEndPoint Start(QuicListenerOptions options)
        {
            List <SslApplicationProtocol> applicationProtocols = options.ServerAuthenticationOptions !.ApplicationProtocols !;
            IPEndPoint listenEndPoint = options.ListenEndPoint !;

            Internals.SocketAddress address = IPEndPointExtensions.Serialize(listenEndPoint);

            uint status;

            Debug.Assert(_stateHandle.IsAllocated);

            MemoryHandle[]? handles = null;
            QuicBuffer[]? buffers   = null;
            try
            {
                Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
                MsQuicAlpnHelper.Prepare(applicationProtocols, out handles, out buffers);
                fixed(byte *paddress = address.Buffer)
                {
                    status = MsQuicApi.Api.ListenerStartDelegate(_state.Handle, (QuicBuffer *)Marshal.UnsafeAddrOfPinnedArrayElement(buffers, 0), (uint)applicationProtocols.Count, paddress);
                }
            }
            catch
            {
                _stateHandle.Free();
                throw;
            }
            finally
            {
                MsQuicAlpnHelper.Return(ref handles, ref buffers);
            }

            QuicExceptionHelpers.ThrowIfFailed(status, "ListenerStart failed.");

            Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
            return(MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, _state.Handle, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS));
        }
示例#6
0
 public CachedSerializedEndPoint(IPAddress address)
 {
     IPEndPoint    = new IPEndPoint(address, 0);
     SocketAddress = IPEndPointExtensions.Serialize(IPEndPoint);
 }
示例#7
0
        // Any exceptions that escape synchronously will be caught by the caller and wrapped in a PingException.
        // We do not need to or want to capture such exceptions into the returned task.
        private Task <PingReply> SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions options)
        {
            var tcs = new TaskCompletionSource <PingReply>();

            _taskCompletionSource = tcs;

            _ipv6     = (address.AddressFamily == AddressFamily.InterNetworkV6);
            _sendSize = buffer.Length;

            // Get and cache correct handle.
            if (!_ipv6 && _handlePingV4 == null)
            {
                _handlePingV4 = Interop.IpHlpApi.IcmpCreateFile();
                if (_handlePingV4.IsInvalid)
                {
                    _handlePingV4 = null;
                    throw new Win32Exception();                     // Gets last error.
                }
            }
            else if (_ipv6 && _handlePingV6 == null)
            {
                _handlePingV6 = Interop.IpHlpApi.Icmp6CreateFile();
                if (_handlePingV6.IsInvalid)
                {
                    _handlePingV6 = null;
                    throw new Win32Exception();                     // Gets last error.
                }
            }

            var ipOptions = new Interop.IpHlpApi.IPOptions(options);

            if (_replyBuffer == null)
            {
                _replyBuffer = SafeLocalAllocHandle.LocalAlloc(MaxUdpPacket);
            }

            // Queue the event.
            int error;

            try
            {
                if (_pingEvent == null)
                {
                    _pingEvent = new ManualResetEvent(false);
                }
                else
                {
                    _pingEvent.Reset();
                }

                _registeredWait = ThreadPool.RegisterWaitForSingleObject(_pingEvent, (state, _) => ((Ping)state).PingCallback(), this, -1, true);

                SetUnmanagedStructures(buffer);

                if (!_ipv6)
                {
                    SafeWaitHandle pingEventSafeWaitHandle = _pingEvent.GetSafeWaitHandle();
                    error = (int)Interop.IpHlpApi.IcmpSendEcho2(
                        _handlePingV4,
                        pingEventSafeWaitHandle,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        (uint)address.GetAddress(),
                        _requestBuffer,
                        (ushort)buffer.Length,
                        ref ipOptions,
                        _replyBuffer,
                        MaxUdpPacket,
                        (uint)timeout);
                }
                else
                {
                    IPEndPoint ep = new IPEndPoint(address, 0);
                    SystemNet.Internals.SocketAddress remoteAddr = IPEndPointExtensions.Serialize(ep);
                    byte[] sourceAddr = new byte[28];

                    SafeWaitHandle pingEventSafeWaitHandle = _pingEvent.GetSafeWaitHandle();
                    error = (int)Interop.IpHlpApi.Icmp6SendEcho2(
                        _handlePingV6,
                        pingEventSafeWaitHandle,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        sourceAddr,
                        remoteAddr.Buffer,
                        _requestBuffer,
                        (ushort)buffer.Length,
                        ref ipOptions,
                        _replyBuffer,
                        MaxUdpPacket,
                        (uint)timeout);
                }
            }
            catch
            {
                UnregisterWaitHandle();
                throw;
            }

            if (error == 0)
            {
                error = Marshal.GetLastWin32Error();

                // Only skip Async IO Pending error value.
                if (error != Interop.IpHlpApi.ERROR_IO_PENDING)
                {
                    // Cleanup.
                    FreeUnmanagedStructures();
                    UnregisterWaitHandle();

                    throw new Win32Exception(error);
                }
            }

            return(tcs.Task);
        }
示例#8
0
        private PingReply InternalSend(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool async)
        {
            _ipv6     = (address.AddressFamily == AddressFamily.InterNetworkV6) ? true : false;
            _sendSize = buffer.Length;

            // Get and cache correct handle.
            if (!_ipv6 && _handlePingV4 == null)
            {
                _handlePingV4 = Interop.IpHlpApi.IcmpCreateFile();
                if (_handlePingV4.IsInvalid)
                {
                    _handlePingV4 = null;
                    throw new Win32Exception(); // Gets last error.
                }
            }
            else if (_ipv6 && _handlePingV6 == null)
            {
                _handlePingV6 = Interop.IpHlpApi.Icmp6CreateFile();
                if (_handlePingV6.IsInvalid)
                {
                    _handlePingV6 = null;
                    throw new Win32Exception(); // Gets last error.
                }
            }

            var ipOptions = new Interop.IpHlpApi.IPOptions(options);

            if (_replyBuffer == null)
            {
                _replyBuffer = SafeLocalAllocHandle.LocalAlloc(MaxUdpPacket);
            }

            // Queue the event.
            int error;

            try
            {
                if (async)
                {
                    if (pingEvent == null)
                    {
                        pingEvent = new ManualResetEvent(false);
                    }
                    else
                    {
                        pingEvent.Reset();
                    }

                    _registeredWait = ThreadPool.RegisterWaitForSingleObject(pingEvent, new WaitOrTimerCallback(PingCallback), this, -1, true);
                }

                SetUnmanagedStructures(buffer);

                if (!_ipv6)
                {
                    if (async)
                    {
                        SafeWaitHandle pingEventSafeWaitHandle = pingEvent.GetSafeWaitHandle();
                        error = (int)Interop.IpHlpApi.IcmpSendEcho2(
                            _handlePingV4,
                            pingEventSafeWaitHandle,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            (uint)address.GetAddress(),
                            _requestBuffer,
                            (ushort)buffer.Length,
                            ref ipOptions,
                            _replyBuffer,
                            MaxUdpPacket,
                            (uint)timeout);
                    }
                    else
                    {
                        error = (int)Interop.IpHlpApi.IcmpSendEcho2(
                            _handlePingV4,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            (uint)address.GetAddress(),
                            _requestBuffer,
                            (ushort)buffer.Length,
                            ref ipOptions,
                            _replyBuffer,
                            MaxUdpPacket,
                            (uint)timeout);
                    }
                }
                else
                {
                    IPEndPoint ep = new IPEndPoint(address, 0);
                    Internals.SocketAddress remoteAddr = IPEndPointExtensions.Serialize(ep);
                    byte[] sourceAddr = new byte[28];
                    if (async)
                    {
                        SafeWaitHandle pingEventSafeWaitHandle = pingEvent.GetSafeWaitHandle();
                        error = (int)Interop.IpHlpApi.Icmp6SendEcho2(
                            _handlePingV6,
                            pingEventSafeWaitHandle,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            sourceAddr,
                            remoteAddr.Buffer,
                            _requestBuffer,
                            (ushort)buffer.Length,
                            ref ipOptions,
                            _replyBuffer,
                            MaxUdpPacket,
                            (uint)timeout);
                    }
                    else
                    {
                        error = (int)Interop.IpHlpApi.Icmp6SendEcho2(
                            _handlePingV6,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            sourceAddr,
                            remoteAddr.Buffer,
                            _requestBuffer,
                            (ushort)buffer.Length,
                            ref ipOptions,
                            _replyBuffer,
                            MaxUdpPacket,
                            (uint)timeout);
                    }
                }
            }
            catch
            {
                UnregisterWaitHandle();
                throw;
            }

            if (error == 0)
            {
                error = Marshal.GetLastWin32Error();

                // Only skip Async IO Pending error value.
                if (async && error == Interop.IpHlpApi.ERROR_IO_PENDING)
                {
                    // Expected async return value.
                    return(null);
                }

                // Cleanup.
                FreeUnmanagedStructures();
                UnregisterWaitHandle();

                if (async || // No IPStatus async errors.
                    error < (int)IPStatus.DestinationNetworkUnreachable || // Min
                    error > (int)IPStatus.DestinationScopeMismatch)    // Max or Out of IPStatus range.
                {
                    throw new Win32Exception(error);
                }

                return(new PingReply((IPStatus)error)); // Synchronous IPStatus errors.
            }

            if (async)
            {
                return(null);
            }

            FreeUnmanagedStructures();

            PingReply reply;

            if (_ipv6)
            {
                Interop.IpHlpApi.Icmp6EchoReply icmp6Reply = Marshal.PtrToStructure <Interop.IpHlpApi.Icmp6EchoReply>(_replyBuffer.DangerousGetHandle());
                reply = new PingReply(icmp6Reply, _replyBuffer.DangerousGetHandle(), _sendSize);
            }
            else
            {
                Interop.IpHlpApi.IcmpEchoReply icmpReply = Marshal.PtrToStructure <Interop.IpHlpApi.IcmpEchoReply>(_replyBuffer.DangerousGetHandle());
                reply = new PingReply(icmpReply);
            }

            // IcmpEchoReply still has an unsafe IntPtr reference into replybuffer
            // and replybuffer was being freed prematurely by the GC, causing AccessViolationExceptions.
            GC.KeepAlive(_replyBuffer);

            return(reply);
        }