/// <summary> /// Initializes a new instance of an inbound <see cref="QuicStream" />. /// </summary> /// <param name="connectionState">Connection state</param> /// <param name="connectionHandle"><see cref="QuicConnection"/> safe handle, used to increment/decrement reference count with each associated stream.</param> /// <param name="handle">Native handle.</param> /// <param name="flags">Related data from the PEER_STREAM_STARTED connection event.</param> /// <param name="defaultErrorCode">Error code used when the stream needs to abort read or write side of the stream internally.</param> internal unsafe QuicStream(QuicConnection.State connectionState, MsQuicContextSafeHandle connectionHandle, QUIC_HANDLE *handle, QUIC_STREAM_OPEN_FLAGS flags, long defaultErrorCode) { _connectionState = connectionState; GCHandle context = GCHandle.Alloc(this, GCHandleType.Weak); try { delegate * unmanaged[Cdecl] < QUIC_HANDLE *, void *, QUIC_STREAM_EVENT *, int > nativeCallback = &NativeCallback; MsQuicApi.Api.ApiTable->SetCallbackHandler( handle, nativeCallback, (void *)GCHandle.ToIntPtr(context)); _handle = new MsQuicContextSafeHandle(handle, context, MsQuicApi.Api.ApiTable->StreamClose, SafeHandleType.Stream, connectionHandle); } catch { context.Free(); throw; } _defaultErrorCode = defaultErrorCode; _canRead = true; _canWrite = !flags.HasFlag(QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL); if (!_canWrite) { _sendTcs.TrySetResult(final: true); } _id = (long)GetMsQuicParameter <ulong>(_handle, QUIC_PARAM_STREAM_ID); _type = flags.HasFlag(QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL) ? QuicStreamType.Unidirectional : QuicStreamType.Bidirectional; _startedTcs.TrySetResult(); }
/// <summary> /// Initializes a new instance of an outbound <see cref="QuicStream" />. /// </summary> /// <param name="connectionState">Connection state</param> /// <param name="connectionHandle"><see cref="QuicConnection"/> safe handle, used to increment/decrement reference count with each associated stream.</param> /// <param name="type">The type of the stream to open.</param> /// <param name="defaultErrorCode">Error code used when the stream needs to abort read or write side of the stream internally.</param> internal unsafe QuicStream(QuicConnection.State connectionState, MsQuicContextSafeHandle connectionHandle, QuicStreamType type, long defaultErrorCode) { _connectionState = connectionState; GCHandle context = GCHandle.Alloc(this, GCHandleType.Weak); try { QUIC_HANDLE *handle; ThrowHelper.ThrowIfMsQuicError(MsQuicApi.Api.ApiTable->StreamOpen( connectionHandle.QuicHandle, type == QuicStreamType.Unidirectional ? QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL : QUIC_STREAM_OPEN_FLAGS.NONE, &NativeCallback, (void *)GCHandle.ToIntPtr(context), &handle), "StreamOpen failed"); _handle = new MsQuicContextSafeHandle(handle, context, MsQuicApi.Api.ApiTable->StreamClose, SafeHandleType.Stream, connectionHandle); } catch { context.Free(); throw; } _defaultErrorCode = defaultErrorCode; _canRead = type == QuicStreamType.Bidirectional; _canWrite = true; if (!_canRead) { _receiveTcs.TrySetResult(final: true); } _type = type; }
/// <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); }
/// <summary> /// Initializes a new instance of an outbound <see cref="QuicConnection" />. /// </summary> private unsafe QuicConnection() { GCHandle context = GCHandle.Alloc(this, GCHandleType.Weak); try { QUIC_HANDLE *handle; ThrowHelper.ThrowIfMsQuicError(MsQuicApi.Api.ApiTable->ConnectionOpen( MsQuicApi.Api.Registration.QuicHandle, &NativeCallback, (void *)GCHandle.ToIntPtr(context), &handle), "ConnectionOpen failed"); _handle = new MsQuicContextSafeHandle(handle, context, MsQuicApi.Api.ApiTable->ConnectionClose, SafeHandleType.Connection); } catch { context.Free(); throw; } }
/// <summary> /// Initializes a new instance of an inbound <see cref="QuicConnection" />. /// </summary> /// <param name="handle">Native handle.</param> /// <param name="info">Related data from the NEW_CONNECTION listener event.</param> internal unsafe QuicConnection(QUIC_HANDLE *handle, QUIC_NEW_CONNECTION_INFO *info) { GCHandle context = GCHandle.Alloc(this, GCHandleType.Weak); try { delegate * unmanaged[Cdecl] < QUIC_HANDLE *, void *, QUIC_CONNECTION_EVENT *, int > nativeCallback = &NativeCallback; MsQuicApi.Api.ApiTable->SetCallbackHandler( handle, nativeCallback, (void *)GCHandle.ToIntPtr(context)); _handle = new MsQuicContextSafeHandle(handle, context, MsQuicApi.Api.ApiTable->ConnectionClose, SafeHandleType.Connection); } catch { context.Free(); throw; } _remoteEndPoint = info->RemoteAddress->ToIPEndPoint(); _localEndPoint = info->LocalAddress->ToIPEndPoint(); }