Example #1
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);
        }
Example #2
0
    /// <summary>
    /// Initializes and starts a new instance of a <see cref="QuicListener" />.
    /// </summary>
    /// <param name="options">Options to start the listener.</param>
    private unsafe QuicListener(QuicListenerOptions options)
    {
        GCHandle context = GCHandle.Alloc(this, GCHandleType.Weak);

        try
        {
            QUIC_HANDLE *handle;
            ThrowHelper.ThrowIfMsQuicError(MsQuicApi.Api.ApiTable->ListenerOpen(
                                               MsQuicApi.Api.Registration.QuicHandle,
                                               &NativeCallback,
                                               (void *)GCHandle.ToIntPtr(context),
                                               &handle),
                                           "ListenerOpen failed");
            _handle = new MsQuicContextSafeHandle(handle, context, MsQuicApi.Api.ApiTable->ListenerClose, SafeHandleType.Listener);
        }
        catch
        {
            context.Free();
            throw;
        }

        // Save the connection options before starting the listener
        _connectionOptionsCallback = options.ConnectionOptionsCallback;
        _acceptQueue = Channel.CreateBounded <PendingConnection>(new BoundedChannelOptions(options.ListenBacklog)
        {
            SingleWriter = true
        });

        // Start the listener, from now on MsQuic events will come.
        using MsQuicBuffers alpnBuffers = new MsQuicBuffers();
        alpnBuffers.Initialize(options.ApplicationProtocols, applicationProtocol => applicationProtocol.Protocol);
        QuicAddr address = options.ListenEndPoint.ToQuicAddr();

        if (options.ListenEndPoint.Address.Equals(IPAddress.IPv6Any))
        {
            // For IPv6Any, MsQuic would listen only for IPv6 connections. This would make it impossible
            // to connect the listener by using the IPv4 address (which could have been e.g. resolved by DNS).
            // Using the Unspecified family makes MsQuic handle connections from all IP addresses.
            address.Family = QUIC_ADDRESS_FAMILY_UNSPEC;
        }
        ThrowHelper.ThrowIfMsQuicError(MsQuicApi.Api.ApiTable->ListenerStart(
                                           _handle.QuicHandle,
                                           alpnBuffers.Buffers,
                                           (uint)alpnBuffers.Count,
                                           &address),
                                       "ListenerStart failed");

        // Get the actual listening endpoint.
        address       = GetMsQuicParameter <QuicAddr>(_handle, QUIC_PARAM_LISTENER_LOCAL_ADDRESS);
        LocalEndPoint = address.ToIPEndPoint(options.ListenEndPoint.AddressFamily);
    }
Example #3
0
        private unsafe IPEndPoint Start(QuicListenerOptions options)
        {
            List <SslApplicationProtocol> applicationProtocols = options.ServerAuthenticationOptions !.ApplicationProtocols !;
            IPEndPoint listenEndPoint = options.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);

                QuicAddr address = listenEndPoint.ToQuicAddr();

                if (listenEndPoint.Address.Equals(IPAddress.IPv6Any))
                {
                    // For IPv6Any, MsQuic would listen only for IPv6 connections. This would make it impossible
                    // to connect the listener by using the IPv4 address (which could have been e.g. resolved by DNS).
                    // Using the Unspecified family makes MsQuic handle connections from all IP addresses.
                    address.Family = QUIC_ADDRESS_FAMILY_UNSPEC;
                }

                ThrowIfFailure(MsQuicApi.Api.ApiTable->ListenerStart(
                                   _state.Handle.QuicHandle,
                                   msquicBuffers.Buffers,
                                   (uint)applicationProtocols.Count,
                                   &address), "ListenerStart failed");
            }
            catch
            {
                _stateHandle.Free();
                throw;
            }

            Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)");
            // override the address family to the original value in case we had to use UNSPEC
            return(MsQuicParameterHelpers.GetIPEndPointParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LISTENER_LOCAL_ADDRESS, listenEndPoint.AddressFamily));
        }