| File: ServerTlsContexts.cs | Web Access |
| Project: src\aspnetcore\src\Servers\Kestrel\Transport.DirectTls\src\Microsoft.AspNetCore.Server.Kestrel.Transport.DirectTls.csproj (Microsoft.AspNetCore.Server.Kestrel.Transport.DirectTls) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.DirectTls; /// <summary> /// Owns the native <see cref="TlsContext"/> instances created for a single listener: the credential-less /// bootstrap context that drives the deferred SNI handshake, plus the per-certificate contexts the SNI /// resolver creates on demand. /// </summary> /// <remarks> /// Each <see cref="TlsContext"/> acquires OpenSSL server credentials, so they must be disposed when the /// listener is torn down or they leak for the process lifetime. Disposal is idempotent and MUST run only /// after the pump threads have stopped, so no in-flight handshake can still be using one of these contexts. /// The per-certificate dictionary is the live instance shared with the resolver closure, so disposal sees /// every context created up to that point. /// </remarks> internal sealed class ServerTlsContexts : IDisposable { private readonly TlsContext _bootstrapContext; private readonly ConcurrentDictionary<X509Certificate2, TlsContext> _perCertificateContexts; private int _disposed; public ServerTlsContexts( TlsContext bootstrapContext, ConcurrentDictionary<X509Certificate2, TlsContext> perCertificateContexts) { ArgumentNullException.ThrowIfNull(bootstrapContext); ArgumentNullException.ThrowIfNull(perCertificateContexts); _bootstrapContext = bootstrapContext; _perCertificateContexts = perCertificateContexts; } public void Dispose() { // Guard so each native context is freed exactly once even if the listener's DisposeAsync runs twice. if (Interlocked.Exchange(ref _disposed, 1) != 0) { return; } _bootstrapContext.Dispose(); foreach (var context in _perCertificateContexts.Values) { context.Dispose(); } _perCertificateContexts.Clear(); } }