Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Managed SNI on Windows with AppContext switch #477

Merged
merged 12 commits into from
Mar 23, 2020
7 changes: 7 additions & 0 deletions BUILDGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Tests can be built and run with custom Target Frameworks. See the below examples
# Build the tests for custom TargetFramework (.NET Core)
# Applicable values: netcoreapp2.1 | netcoreapp2.2 | netcoreapp3.0
```

### Running Tests:

```bash
Expand All @@ -171,3 +172,9 @@ Tests can be built and run with custom Target Frameworks. See the below examples
# Use above property to run Functional Tests with custom TargetFramework (.NET Core)
# Applicable values: netcoreapp2.1 | netcoreapp2.2 | netcoreapp3.0
```

## Using Managed SNI on Windows

Managed SNI can be enabled on Windows by enabling below AppContext switch:
David-Engel marked this conversation as resolved.
Show resolved Hide resolved

**"Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows"**
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,15 @@ namespace Microsoft.Data.SqlClient
{
internal sealed class TdsParserStateObjectFactory
{

private const string UseLegacyNetworkingOnWindows = "Microsoft.Data.SqlClient.UseLegacyNetworkingOnWindows";

public static readonly TdsParserStateObjectFactory Singleton = new TdsParserStateObjectFactory();

private const string UseManagedNetworkingOnWindows = "Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows";

// Temporary disabling App Context switching for managed SNI.
// If the appcontext switch is set then Use Managed SNI based on the value. Otherwise Managed SNI should always be used.
//private static bool shouldUseLegacyNetorking;
//public static bool UseManagedSNI { get; } = AppContext.TryGetSwitch(UseLegacyNetworkingOnWindows, out shouldUseLegacyNetorking) ? !shouldUseLegacyNetorking : true;
private static bool shouldUseManagedSNI;

#if DEBUG
private static Lazy<bool> useManagedSNIOnWindows = new Lazy<bool>(
() => bool.TrueString.Equals(Environment.GetEnvironmentVariable("Microsoft.Data.SqlClient.UseManagedSNIOnWindows"), StringComparison.InvariantCultureIgnoreCase)
);
public static bool UseManagedSNI => useManagedSNIOnWindows.Value;
#else
public static bool UseManagedSNI { get; } = false;
#endif
// If the appcontext switch is set then Use Managed SNI based on the value. Otherwise Native SNI.dll will be used by default.
public static bool UseManagedSNI { get; } =
AppContext.TryGetSwitch(UseManagedNetworkingOnWindows, out shouldUseManagedSNI) ? shouldUseManagedSNI : false;

public EncryptionOptions EncryptionOptions
{
Expand All @@ -49,10 +39,14 @@ public TdsParserStateObject CreateTdsParserStateObject(TdsParser parser)
{
if (UseManagedSNI)
{
SqlClientEventSource.Log.TraceEvent("<sc.TdsParserStateObjectFactory.CreateTdsParserStateObject|INFO> Found AppContext switch '{0}#' enabled, managed networking implementation will be used."
, UseManagedNetworkingOnWindows);
return new TdsParserStateObjectManaged(parser);
}
else
{
SqlClientEventSource.Log.TraceEvent("<sc.TdsParserStateObjectFactory.CreateTdsParserStateObject|INFO> AppContext switch '{0}#' not enabled, native networking implementation will be used."
, UseManagedNetworkingOnWindows);
return new TdsParserStateObjectNative(parser);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ public static class DataTestUtility
public const string UdtTestDbName = "UdtTestDb";
public const string AKVKeyName = "TestSqlClientAzureKeyVaultProvider";

private static readonly Assembly MdsAssembly = typeof(Microsoft.Data.SqlClient.SqlConnection).GetTypeInfo().Assembly;
private static readonly Type TdsParserStateObjectFactoryInstance = MdsAssembly?.GetType("Microsoft.Data.SqlClient.TdsParserStateObjectFactory");
private static readonly PropertyInfo UseManagedSni = TdsParserStateObjectFactoryInstance?.GetProperty("UseManagedSNI", BindingFlags.Static | BindingFlags.Public);
private const string ManagedNetworkingAppContextSwitch = "Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows";

private static bool UseManagedSNI =
bool.TryParse(Environment.GetEnvironmentVariable("Microsoft_Data_SqlClient_UseManagedSniOnWindows"), out UseManagedSNI) ? UseManagedSNI : false;

private static readonly string[] AzureSqlServerEndpoints = {".database.windows.net",
".database.cloudapi.de",
Expand Down Expand Up @@ -76,6 +77,12 @@ private class Config

static DataTestUtility()
{
if (UseManagedSNI)
{
AppContext.SetSwitch(ManagedNetworkingAppContextSwitch, true);
Console.WriteLine($"App Context switch {ManagedNetworkingAppContextSwitch} enabled on {Environment.OSVersion}");
}

using (StreamReader r = new StreamReader("config.json"))
{
string json = r.ReadToEnd();
Expand Down Expand Up @@ -231,7 +238,7 @@ public static bool IsAKVSetupAvailable()
return !string.IsNullOrEmpty(AKVUrl) && !string.IsNullOrEmpty(AKVClientId) && !string.IsNullOrEmpty(AKVClientSecret);
}

public static bool IsUsingManagedSNI() => (bool)(UseManagedSni?.GetValue(null) ?? false);
public static bool IsUsingManagedSNI() => UseManagedSNI;

public static bool IsUsingNativeSNI() => !IsUsingManagedSNI();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests
public static class IntegratedAuthenticationTest
{
private static bool IsIntegratedSecurityEnvironmentSet() => DataTestUtility.IsIntegratedSecuritySetup();
private static bool AreConnectionStringsSetup() => DataTestUtility.AreConnStringsSetup();

private static bool AreConnectionStringsSetup() => DataTestUtility.AreConnStringsSetup();

[ConditionalFact(nameof(IsIntegratedSecurityEnvironmentSet), nameof(AreConnectionStringsSetup))]
public static void IntegratedAuthenticationTestWithConnectionPooling()
Expand Down