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); }
/// <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); }
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)); }