Skip to content

Commit

Permalink
v1.2.5 - add ConnectionStringBuilder CertificateValidation/Certificat…
Browse files Browse the repository at this point in the history
…eSelection;#164
  • Loading branch information
2881099 committed Nov 15, 2023
1 parent 77a5ae4 commit 723246a
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AssemblyName>FreeRedis.DistributedCache</AssemblyName>
<PackageId>FreeRedis.DistributedCache</PackageId>
<RootNamespace>FreeRedis.DistributedCache</RootNamespace>
<Version>1.2.3</Version>
<Version>1.2.5</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/2881099/FreeRedis</PackageProjectUrl>
<Description>分布式缓存 FreeRedis 实现 Microsoft.Extensions.Caching</Description>
Expand Down
4 changes: 4 additions & 0 deletions src/FreeRedis/ConnectionStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Text;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -34,6 +35,9 @@ public string Host
public bool ExitAutoDisposePool { get; set; } = true;
public bool SubscribleReadbytes { get; set; } = false;

public RemoteCertificateValidationCallback CertificateValidation;
public LocalCertificateSelectionCallback CertificateSelection;

public static implicit operator ConnectionStringBuilder(string connectionString) => Parse(connectionString);
public static implicit operator string(ConnectionStringBuilder connectionString) => connectionString.ToString();

Expand Down
2 changes: 1 addition & 1 deletion src/FreeRedis/FreeRedis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<AssemblyName>FreeRedis</AssemblyName>
<PackageId>FreeRedis</PackageId>
<RootNamespace>FreeRedis</RootNamespace>
<Version>1.2.3</Version>
<Version>1.2.5</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/2881099/FreeRedis</PackageProjectUrl>
<Description>FreeRedis is .NET redis client, supports cluster, sentinel, master-slave, pipeline, transaction and connection pool.</Description>
Expand Down
2 changes: 1 addition & 1 deletion src/FreeRedis/FreeRedis.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions src/FreeRedis/Internal/DefaultRedisSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,15 @@ public TimeSpan SendTimeout

public RedisProtocol Protocol { get; set; } = RedisProtocol.RESP2;
public Encoding Encoding { get; set; } = Encoding.UTF8;
RemoteCertificateValidationCallback _certificateValidation;
LocalCertificateSelectionCallback _certificateSelection;

public DefaultRedisSocket(string host, bool ssl)
public DefaultRedisSocket(string host, bool ssl, RemoteCertificateValidationCallback certificateValidation, LocalCertificateSelectionCallback certificateSelection)
{
Host = host;
Ssl = ssl;
_certificateValidation = certificateValidation;
_certificateSelection = certificateSelection;
}

void WriteAfter(CommandPacket cmd)
Expand Down Expand Up @@ -261,7 +265,7 @@ public void Connect()
_netStream = new NetworkStream(Socket, true);
if (Ssl)
{
_sslStream = new SslStream(_netStream, true);
_sslStream = new SslStream(_netStream, true, _certificateValidation, _certificateSelection);
var stringHostOnly = endpoint is DnsEndPoint ep1 ? ep1.Host :
(endpoint is IPEndPoint ep2 ? ep2.Address.ToString() : "");
_sslStream.AuthenticateAsClient(stringHostOnly);
Expand Down
74 changes: 29 additions & 45 deletions src/FreeRedis/Internal/RedisClientPool.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
using FreeRedis.Internal.ObjectPool;
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace FreeRedis.Internal
{
public class RedisClientPool : ObjectPool<RedisClient>, IDisposable
{
public RedisClientPool(string connectionString, RedisClient topOwner) : base(null)
public RedisClientPool(ConnectionStringBuilder connectionString, RedisClient topOwner) : base(null)
{
_policy = new RedisClientPoolPolicy
{
Expand All @@ -27,18 +20,18 @@ public RedisClientPool(string connectionString, RedisClient topOwner) : base(nul
var cli = s as RedisClient;
var rds = cli.Adapter.GetRedisSocket(null);
var adapter = cli.Adapter as RedisClient.SingleInsideAdapter;
rds.Socket.ReceiveTimeout = (int)_policy._connectionStringBuilder.ReceiveTimeout.TotalMilliseconds;
rds.Socket.SendTimeout = (int)_policy._connectionStringBuilder.SendTimeout.TotalMilliseconds;
rds.Encoding = _policy._connectionStringBuilder.Encoding;
rds.Socket.ReceiveTimeout = (int)connectionString.ReceiveTimeout.TotalMilliseconds;
rds.Socket.SendTimeout = (int)connectionString.SendTimeout.TotalMilliseconds;
rds.Encoding = connectionString.Encoding;
var isIgnoreAop = rds.LastCommand.IsIgnoreAop;

var cmds = new List<CommandPacket>();
if (_policy._connectionStringBuilder.Protocol == RedisProtocol.RESP3)
if (connectionString.Protocol == RedisProtocol.RESP3)
{
//未开启 ACL 的情况
if (string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.User) && !string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.Password))
if (string.IsNullOrWhiteSpace(connectionString.User) && !string.IsNullOrWhiteSpace(connectionString.Password))
cmds.Add("AUTH".SubCommand(null)
.Input(_policy._connectionStringBuilder.Password)
.Input(connectionString.Password)
.OnData(rt =>
{
if (rt.IsError && rt.SimpleError != "ERR Client sent AUTH, but no password is set")
Expand All @@ -47,47 +40,47 @@ public RedisClientPool(string connectionString, RedisClient topOwner) : base(nul
}));
cmds.Add("HELLO"
.Input(3)
.InputIf(!string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.User) && !string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.Password), "AUTH", _policy._connectionStringBuilder.User, _policy._connectionStringBuilder.Password)
.InputIf(!string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.ClientName), "SETNAME", _policy._connectionStringBuilder.ClientName)
.InputIf(!string.IsNullOrWhiteSpace(connectionString.User) && !string.IsNullOrWhiteSpace(connectionString.Password), "AUTH", connectionString.User, connectionString.Password)
.InputIf(!string.IsNullOrWhiteSpace(connectionString.ClientName), "SETNAME", connectionString.ClientName)
.OnData(rt =>
{
rt.ThrowOrNothing();
rds.Protocol = RedisProtocol.RESP3;
}));
}
else if (!string.IsNullOrEmpty(_policy._connectionStringBuilder.User) && !string.IsNullOrEmpty(_policy._connectionStringBuilder.Password))
else if (!string.IsNullOrEmpty(connectionString.User) && !string.IsNullOrEmpty(connectionString.Password))
cmds.Add("AUTH".SubCommand(null)
.InputIf(!string.IsNullOrWhiteSpace(_policy._connectionStringBuilder.User), _policy._connectionStringBuilder.User)
.Input(_policy._connectionStringBuilder.Password)
.InputIf(!string.IsNullOrWhiteSpace(connectionString.User), connectionString.User)
.Input(connectionString.Password)
.OnData(rt =>
{
rt.ThrowOrNothing();
}));
else if (!string.IsNullOrEmpty(_policy._connectionStringBuilder.Password))
else if (!string.IsNullOrEmpty(connectionString.Password))
cmds.Add("AUTH".SubCommand(null)
.Input(_policy._connectionStringBuilder.Password)
.Input(connectionString.Password)
.OnData(rt =>
{
if (rt.IsError && rt.SimpleError != "ERR Client sent AUTH, but no password is set")
rt.ThrowOrNothing();
}));

if (_policy._connectionStringBuilder.Database > 0)
cmds.Add("SELECT".Input(_policy._connectionStringBuilder.Database)
if (connectionString.Database > 0)
cmds.Add("SELECT".Input(connectionString.Database)
.OnData(rt =>
{
if (rt.IsError)
{
if (rt.SimpleError == "ERR SELECT is not allowed in cluster mode")
_policy._connectionStringBuilder.Database = 0;
connectionString.Database = 0;
else
rt.ThrowOrNothing();
}
(rds as IRedisSocketModify).SetDatabase(_policy._connectionStringBuilder.Database);
(rds as IRedisSocketModify).SetDatabase(connectionString.Database);
}));

if (!string.IsNullOrEmpty(_policy._connectionStringBuilder.ClientName) && _policy._connectionStringBuilder.Protocol == RedisProtocol.RESP2)
cmds.Add("CLIENT".SubCommand("SETNAME").InputRaw(_policy._connectionStringBuilder.ClientName)
if (!string.IsNullOrEmpty(connectionString.ClientName) && connectionString.Protocol == RedisProtocol.RESP2)
cmds.Add("CLIENT".SubCommand("SETNAME").InputRaw(connectionString.ClientName)
.OnData(rt =>
{
rt.ThrowOrNothing();
Expand Down Expand Up @@ -126,13 +119,15 @@ public RedisClientPool(string connectionString, RedisClient topOwner) : base(nul
}, false, true); //aop after
});

topOwner?.OnConnected(TopOwner, new ConnectedEventArgs(_policy._connectionStringBuilder.Host, this, cli));
topOwner?.OnConnected(TopOwner, new ConnectedEventArgs(connectionString.Host, this, cli));
if (isIgnoreAop == false)
topOwner?.OnNotice(TopOwner, new NoticeEventArgs(NoticeType.Info, null, $"{_policy._connectionStringBuilder.Host.PadRight(21)} > Connected, ClientId: {rds.ClientId}, Database: {rds.Database}, Pool: {_freeObjects.Count}/{_allObjects.Count}", cli));
topOwner?.OnNotice(TopOwner, new NoticeEventArgs(NoticeType.Info, null, $"{connectionString.Host.PadRight(21)} > Connected, ClientId: {rds.ClientId}, Database: {rds.Database}, Pool: {_freeObjects.Count}/{_allObjects.Count}", cli));
};
this.Policy = _policy;
this.TopOwner = topOwner;
_policy.ConnectionString = connectionString;
_policy._connectionStringBuilder = connectionString;
if (connectionString.MinPoolSize > 0)
RedisClientPoolPolicy.PrevReheatConnectionPool(this, connectionString.MinPoolSize);
}

internal bool CheckAvailable() => base.LiveCheckAvailable();
Expand All @@ -159,18 +154,6 @@ public class RedisClientPoolPolicy : IPolicy<RedisClient>
public bool IsAutoDisposeWithSystem { get => _connectionStringBuilder.ExitAutoDisposePool; set => _connectionStringBuilder.ExitAutoDisposePool = value; }
public int CheckAvailableInterval { get; set; } = 5;

public string ConnectionString
{
get => _connectionStringBuilder.ToString();
set
{
_connectionStringBuilder = value;

if (_connectionStringBuilder.MinPoolSize > 0)
PrevReheatConnectionPool(_pool, _connectionStringBuilder.MinPoolSize);
}
}

public bool OnCheckAvailable(Object<RedisClient> obj)
{
obj.ResetValue();
Expand All @@ -179,7 +162,8 @@ public bool OnCheckAvailable(Object<RedisClient> obj)

public RedisClient OnCreate()
{
return new RedisClient(_pool.TopOwner, _connectionStringBuilder.Host, _connectionStringBuilder.Ssl,
return new RedisClient(_pool.TopOwner, _connectionStringBuilder.Host,
_connectionStringBuilder.Ssl, _connectionStringBuilder.CertificateValidation, _connectionStringBuilder.CertificateSelection,
_connectionStringBuilder.ConnectTimeout,
_connectionStringBuilder.ReceiveTimeout, _connectionStringBuilder.SendTimeout,
cli => Connected(cli, new EventArgs()),
Expand Down
7 changes: 4 additions & 3 deletions src/FreeRedis/RedisClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Security;
using System.Text;
using System.Threading;

namespace FreeRedis
{
Expand Down Expand Up @@ -65,11 +65,12 @@ public RedisClient(ConnectionStringBuilder sentinelConnectionString, string[] se
/// <summary>
/// Single inside RedisClient
/// </summary>
protected internal RedisClient(RedisClient topOwner, string host, bool ssl,
protected internal RedisClient(RedisClient topOwner, string host,
bool ssl, RemoteCertificateValidationCallback certificateValidation, LocalCertificateSelectionCallback certificateSelection,
TimeSpan connectTimeout, TimeSpan receiveTimeout, TimeSpan sendTimeout,
Action<RedisClient> connected, Action<RedisClient> disconnected)
{
Adapter = new SingleInsideAdapter(topOwner ?? this, this, host, ssl,
Adapter = new SingleInsideAdapter(topOwner ?? this, this, host, ssl, certificateValidation, certificateSelection,
connectTimeout, receiveTimeout, sendTimeout, connected, disconnected);
Prefix = topOwner.Prefix;
ConnectionString = topOwner.ConnectionString;
Expand Down
20 changes: 14 additions & 6 deletions src/FreeRedis/RedisClient/Adapter/ClusterAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,16 @@ public override TValue AdapterCall<TValue>(CommandPacket cmd, Func<RedisResult,
{
cmd._clusterMovedTryCount++;

var testConnection = pool._policy._connectionStringBuilder;
if (moved.endpoint.StartsWith("127.0.0.1"))
moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
moved.endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{moved.endpoint.Substring(10)}";
else if (moved.endpoint.StartsWith("localhost", StringComparison.CurrentCultureIgnoreCase))
moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
moved.endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{moved.endpoint.Substring(10)}";

ConnectionStringBuilder connectionString = pool._policy._connectionStringBuilder.ToString();
ConnectionStringBuilder connectionString = testConnection.ToString();
connectionString.Host = moved.endpoint;
connectionString.CertificateValidation = testConnection.CertificateValidation;
connectionString.CertificateSelection = testConnection.CertificateSelection;
RegisterClusterNode(connectionString);

if (moved.ismoved)
Expand Down Expand Up @@ -243,13 +246,16 @@ async public override Task<TValue> AdapterCallAsync<TValue>(CommandPacket cmd, F
{
cmd._clusterMovedTryCount++;

var testConnection = pool._policy._connectionStringBuilder;
if (moved.endpoint.StartsWith("127.0.0.1"))
moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
moved.endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{moved.endpoint.Substring(10)}";
else if (moved.endpoint.StartsWith("localhost", StringComparison.CurrentCultureIgnoreCase))
moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
moved.endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{moved.endpoint.Substring(10)}";

ConnectionStringBuilder connectionString = pool._policy._connectionStringBuilder.ToString();
ConnectionStringBuilder connectionString = testConnection.ToString();
connectionString.Host = moved.endpoint;
connectionString.CertificateValidation = testConnection.CertificateValidation;
connectionString.CertificateSelection = testConnection.CertificateSelection;
RegisterClusterNode(connectionString);

if (moved.ismoved)
Expand Down Expand Up @@ -298,6 +304,8 @@ void RefershClusterNodes()
endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{endpoint.Substring(10)}";
ConnectionStringBuilder connectionString = testConnection.ToString();
connectionString.Host = endpoint;
connectionString.CertificateValidation = testConnection.CertificateValidation;
connectionString.CertificateSelection = testConnection.CertificateSelection;
if (cnodesDict.ContainsKey(endpoint) == false) cnodesDict.Add(endpoint, true);
RegisterClusterNode(connectionString);

Expand Down
Loading

0 comments on commit 723246a

Please sign in to comment.