// outbound. internal MsQuicStream(SafeMsQuicConnectionHandle connection, QUIC_STREAM_OPEN_FLAGS flags) { Debug.Assert(connection != null); _canRead = !flags.HasFlag(QUIC_STREAM_OPEN_FLAGS.UNIDIRECTIONAL); _canWrite = true; _stateHandle = GCHandle.Alloc(_state); try { uint status = MsQuicApi.Api.StreamOpenDelegate( connection, flags, s_streamDelegate, GCHandle.ToIntPtr(_stateHandle), out _state.Handle); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to open stream to peer."); status = MsQuicApi.Api.StreamStartDelegate(_state.Handle, QUIC_STREAM_START_FLAGS.ASYNC); QuicExceptionHelpers.ThrowIfFailed(status, "Could not start stream."); } catch { _state.Handle?.Dispose(); _stateHandle.Free(); throw; } }
// constructor for inbound connections public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SafeMsQuicConnectionHandle handle, bool remoteCertificateRequired = false, X509RevocationMode revocationMode = X509RevocationMode.Offline, RemoteCertificateValidationCallback?remoteCertificateValidationCallback = null, ServerCertificateSelectionCallback?serverCertificateSelectionCallback = null) { _state.Handle = handle; _state.StateGCHandle = GCHandle.Alloc(_state); _state.Connected = true; _state.RemoteCertificateRequired = remoteCertificateRequired; _state.RevocationMode = revocationMode; _state.RemoteCertificateValidationCallback = remoteCertificateValidationCallback; _state.IsServer = true; _localEndPoint = localEndPoint; _remoteEndPoint = remoteEndPoint; try { Debug.Assert(!Monitor.IsEntered(_state)); MsQuicApi.Api.SetCallbackHandlerDelegate( _state.Handle, s_connectionDelegate, GCHandle.ToIntPtr(_state.StateGCHandle)); } catch { _state.StateGCHandle.Free(); throw; } _state.TraceId = MsQuicTraceHelper.GetTraceId(_state.Handle); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{TraceId()} Inbound connection created"); } }
// constructor for inbound connections public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SafeMsQuicConnectionHandle handle) { _state.Handle = handle; _state.StateGCHandle = GCHandle.Alloc(_state); _state.Connected = true; _localEndPoint = localEndPoint; _remoteEndPoint = remoteEndPoint; _remoteCertificateRequired = false; _isServer = true; try { MsQuicApi.Api.SetCallbackHandlerDelegate( _state.Handle, s_connectionDelegate, GCHandle.ToIntPtr(_state.StateGCHandle)); } catch { _state.StateGCHandle.Free(); throw; } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"[Connection#{_state.GetHashCode()}] inbound connection created"); } }
private static unsafe uint NativeCallbackHandler( IntPtr listener, IntPtr context, ref ListenerEvent evt) { if (evt.Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) { return(MsQuicStatusCodes.InternalError); } GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; SafeMsQuicConnectionHandle?connectionHandle = null; try { ref NewConnectionInfo connectionInfo = ref *evt.Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.RemoteAddress); connectionHandle = new SafeMsQuicConnectionHandle(evt.Data.NewConnection.Connection); uint status = MsQuicApi.Api.ConnectionSetConfigurationDelegate(connectionHandle, state.ConnectionConfiguration); QuicExceptionHelpers.ThrowIfFailed(status, "ConnectionSetConfiguration failed."); var msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, connectionHandle, state.RemoteCertificateRequired, state.RevocationMode, state.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.AcceptConnectionQueue.Writer.TryWrite(msQuicConnection)) { // This handle will be cleaned up by MsQuic. connectionHandle.SetHandleAsInvalid(); msQuicConnection.Dispose(); return(MsQuicStatusCodes.InternalError); } return(MsQuicStatusCodes.Success); }
// constructor for inbound connections public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SafeMsQuicConnectionHandle handle, bool remoteCertificateRequired = false, X509RevocationMode revocationMode = X509RevocationMode.Offline, RemoteCertificateValidationCallback?remoteCertificateValidationCallback = null) { _state.Handle = handle; _state.StateGCHandle = GCHandle.Alloc(_state); _state.Connected = true; _isServer = true; _localEndPoint = localEndPoint; _remoteEndPoint = remoteEndPoint; _remoteCertificateRequired = remoteCertificateRequired; _revocationMode = revocationMode; _remoteCertificateValidationCallback = remoteCertificateValidationCallback; if (_remoteCertificateRequired) { // We need to link connection for the validation callback. // We need to be able to find the connection in HandleEventPeerCertificateReceived // and dispatch it as sender to validation callback. // After that Connection will be set back to null. _state.Connection = this; } try { MsQuicApi.Api.SetCallbackHandlerDelegate( _state.Handle, s_connectionDelegate, GCHandle.ToIntPtr(_state.StateGCHandle)); } catch { _state.StateGCHandle.Free(); throw; } _state.TraceId = MsQuicTraceHelper.GetTraceId(_state.Handle); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{TraceId()} Inbound connection created"); } }
// constructor for inbound connections public MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SafeMsQuicConnectionHandle handle) { _state.Handle = handle; _state.Connected = true; _localEndPoint = localEndPoint; _remoteEndPoint = remoteEndPoint; _stateHandle = GCHandle.Alloc(_state); try { MsQuicApi.Api.SetCallbackHandlerDelegate( _state.Handle, s_connectionDelegate, GCHandle.ToIntPtr(_stateHandle)); } catch { _stateHandle.Free(); throw; } }
private static unsafe uint NativeCallbackHandler( IntPtr listener, IntPtr context, ListenerEvent *evt) { GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; if (evt->Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) { return(MsQuicStatusCodes.InternalError); } SafeMsQuicConnectionHandle?connectionHandle = null; MsQuicConnection? msQuicConnection = null; try { ref NewConnectionInfo connectionInfo = ref *evt->Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.RemoteAddress); string targetHost = string.Empty; // compat with SslStream if (connectionInfo.ServerNameLength > 0 && connectionInfo.ServerName != IntPtr.Zero) { // TBD We should figure out what to do with international names. targetHost = Marshal.PtrToStringAnsi(connectionInfo.ServerName, connectionInfo.ServerNameLength); } SafeMsQuicConfigurationHandle?connectionConfiguration = state.ConnectionConfiguration; if (connectionConfiguration == null) { Debug.Assert(state.AuthenticationOptions.ServerCertificateSelectionCallback != null); try { // ServerCertificateSelectionCallback is synchronous. We will call it as needed when building configuration connectionConfiguration = SafeMsQuicConfigurationHandle.Create(state.ConnectionOptions, state.AuthenticationOptions, targetHost); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during creating configuration in connection callback: {ex}"); } } if (connectionConfiguration == null) { // We don't have safe handle yet so MsQuic will cleanup new connection. return(MsQuicStatusCodes.InternalError); } } connectionHandle = new SafeMsQuicConnectionHandle(evt->Data.NewConnection.Connection); uint status = MsQuicApi.Api.ConnectionSetConfigurationDelegate(connectionHandle, connectionConfiguration); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, state, connectionHandle, state.AuthenticationOptions.ClientCertificateRequired, state.AuthenticationOptions.CertificateRevocationCheckMode, state.AuthenticationOptions.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.PendingConnections.TryAdd(connectionHandle.DangerousGetHandle(), msQuicConnection)) { msQuicConnection.Dispose(); } return(MsQuicStatusCodes.Success); } // If we fall-through here something wrong happened. }
// constructor for inbound connections public unsafe MsQuicConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, MsQuicListener.State listenerState, SafeMsQuicConnectionHandle handle, bool remoteCertificateRequired = false, X509RevocationMode revocationMode = X509RevocationMode.Offline, RemoteCertificateValidationCallback?remoteCertificateValidationCallback = null, ServerCertificateSelectionCallback?serverCertificateSelectionCallback = null) { _state.Handle = handle; _state.StateGCHandle = GCHandle.Alloc(_state); _state.RemoteCertificateRequired = remoteCertificateRequired; _state.RevocationMode = revocationMode; _state.RemoteCertificateValidationCallback = remoteCertificateValidationCallback; _state.IsServer = true; _localEndPoint = localEndPoint; _remoteEndPoint = remoteEndPoint; try { Debug.Assert(!Monitor.IsEntered(_state), "!Monitor.IsEntered(_state)"); MsQuicApi.Api.ApiTable->SetConnectionCallback(_state.Handle.QuicHandle, &NativeCallback, (void *)GCHandle.ToIntPtr(_state.StateGCHandle)); } catch { _state.StateGCHandle.Free(); throw; } _state.ListenerState = listenerState; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(_state, $"{handle} Inbound connection created"); } }
#pragma warning restore CS3016 private static unsafe int NativeCallback(QUIC_HANDLE *listener, void *context, QUIC_LISTENER_EVENT *listenerEvent) { GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; if (listenerEvent->Type == QUIC_LISTENER_EVENT_TYPE.STOP_COMPLETE) { state.StopCompletion.TrySetResult(); return(QUIC_STATUS_SUCCESS); } if (listenerEvent->Type != QUIC_LISTENER_EVENT_TYPE.NEW_CONNECTION) { return(QUIC_STATUS_INTERNAL_ERROR); } SafeMsQuicConnectionHandle?connectionHandle = null; MsQuicConnection? msQuicConnection = null; try { ref QUIC_NEW_CONNECTION_INFO connectionInfo = ref *listenerEvent->NEW_CONNECTION.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint((IntPtr)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint((IntPtr)connectionInfo.RemoteAddress); string targetHost = string.Empty; // compat with SslStream if (connectionInfo.ServerNameLength > 0 && (IntPtr)connectionInfo.ServerName != IntPtr.Zero) { // TBD We should figure out what to do with international names. targetHost = Marshal.PtrToStringAnsi((IntPtr)connectionInfo.ServerName, connectionInfo.ServerNameLength); } SafeMsQuicConfigurationHandle?connectionConfiguration = state.ConnectionConfiguration; if (connectionConfiguration == null) { Debug.Assert(state.AuthenticationOptions.ServerCertificateSelectionCallback != null); try { // ServerCertificateSelectionCallback is synchronous. We will call it as needed when building configuration connectionConfiguration = SafeMsQuicConfigurationHandle.Create(state.ConnectionOptions, state.AuthenticationOptions, targetHost); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during creating configuration in connection callback: {ex}"); } } if (connectionConfiguration == null) { // We don't have safe handle yet so MsQuic will cleanup new connection. return(QUIC_STATUS_INTERNAL_ERROR); } } connectionHandle = new SafeMsQuicConnectionHandle(listenerEvent->NEW_CONNECTION.Connection); Debug.Assert(!Monitor.IsEntered(state), "!Monitor.IsEntered(state)"); int status = MsQuicApi.Api.ApiTable->ConnectionSetConfiguration(connectionHandle.QuicHandle, connectionConfiguration.QuicHandle); if (StatusSucceeded(status)) { msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, state, connectionHandle, state.AuthenticationOptions.ClientCertificateRequired, state.AuthenticationOptions.CertificateRevocationCheckMode, state.AuthenticationOptions.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn((IntPtr)connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.PendingConnections.TryAdd(connectionHandle.DangerousGetHandle(), msQuicConnection)) { msQuicConnection.Dispose(); } return(QUIC_STATUS_SUCCESS); } // If we fall-through here something wrong happened. }