Skip to content

Commit 7faad6f

Browse files
author
RS338637
committed
SSL Stream support
1 parent 2b27236 commit 7faad6f

File tree

10 files changed

+138
-48
lines changed

10 files changed

+138
-48
lines changed

Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public interface IMemcachedClientConfiguration
4242

4343
IServerPool CreatePool();
4444

45+
bool UseSslStream { get; }
46+
4547
}
4648
}
4749

Enyim.Caching/Configuration/MemcachedClientConfiguration.cs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ public MemcachedClientConfiguration(
116116
}
117117
}
118118

119+
if (options.UseSslStream != null)
120+
{
121+
UseSslStream = options.UseSslStream;
122+
}
123+
119124
if (!string.IsNullOrEmpty(options.KeyTransformer))
120125
{
121126
try
@@ -179,26 +184,33 @@ private void ConfigureServers(MemcachedClientOptions options)
179184
Servers = new List<EndPoint>();
180185
foreach (var server in options.Servers)
181186
{
182-
if (!IPAddress.TryParse(server.Address, out var address))
187+
if (options.UseSslStream)
183188
{
184-
address = Dns.GetHostAddresses(server.Address)
185-
.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
186-
187-
if (address == null)
189+
AddServer(server.Address, server.Port);
190+
}
191+
else
192+
{
193+
if (!IPAddress.TryParse(server.Address, out var address))
188194
{
189-
_logger.LogError($"Could not resolve host '{server.Address}'.");
195+
address = Dns.GetHostAddresses(server.Address)
196+
.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
197+
198+
if (address == null)
199+
{
200+
_logger.LogError($"Could not resolve host '{server.Address}'.");
201+
}
202+
else
203+
{
204+
_logger.LogInformation($"Memcached server address - {address}");
205+
}
190206
}
191207
else
192208
{
193-
_logger.LogInformation($"Memcached server address - {address}");
209+
_logger.LogInformation($"Memcached server address - {server.Address }:{server.Port}");
194210
}
195-
}
196-
else
197-
{
198-
_logger.LogInformation($"Memcached server address - {server.Address }:{server.Port}");
199-
}
200211

201-
Servers.Add(new IPEndPoint(address, server.Port));
212+
Servers.Add(new IPEndPoint(address, server.Port));
213+
}
202214
}
203215
}
204216

@@ -327,6 +339,8 @@ IServerPool IMemcachedClientConfiguration.CreatePool()
327339
throw new ArgumentOutOfRangeException("Unknown protocol: " + (int)this.Protocol);
328340
}
329341

342+
public bool UseSslStream { get; private set; }
343+
330344
#endregion
331345
}
332346
}

Enyim.Caching/Configuration/MemcachedClientOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class MemcachedClientOptions : IOptions<MemcachedClientOptions>
2121

2222
public string Transcoder { get; set; }
2323

24+
public bool UseSslStream { get; set; }
25+
2426
public IProviderFactory<IMemcachedNodeLocator> NodeLocatorFactory { get; set; }
2527

2628
public MemcachedClientOptions Value => this;

Enyim.Caching/Configuration/SocketPoolConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class SocketPoolConfiguration : ISocketPoolConfiguration
1010
{
1111
private int minPoolSize = 5;
1212
private int maxPoolSize = 100;
13+
private bool useSslStream = false;
1314
private TimeSpan connectionTimeout = new TimeSpan(0, 0, 10);
1415
private TimeSpan receiveTimeout = new TimeSpan(0, 0, 10);
1516
private TimeSpan deadTimeout = new TimeSpan(0, 0, 10);

Enyim.Caching/Enyim.Caching.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<Description>EnyimMemcachedCore is a Memcached client library for .NET Core. Usage: Add services.AddEnyimMemcached(...) and app.UseEnyimMemcached() in Startup. Add IMemcachedClient into constructor.</Description>
55
<Authors>cnblogs.com</Authors>
6-
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
6+
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
77
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
88
<AssemblyName>EnyimMemcachedCore</AssemblyName>
99
<PackageId>EnyimMemcachedCore</PackageId>
@@ -16,11 +16,11 @@
1616
</PropertyGroup>
1717

1818
<ItemGroup>
19-
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
20-
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
21-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
22-
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
23-
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
19+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
20+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
21+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
22+
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
23+
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
2424
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
2525
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.2" />
2626
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />

Enyim.Caching/Memcached/DefaultServerPool.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public DefaultServerPool(
5050

5151
protected virtual IMemcachedNode CreateNode(EndPoint endpoint)
5252
{
53-
return new MemcachedNode(endpoint, this.configuration.SocketPool, _logger);
53+
return new MemcachedNode(endpoint, this.configuration.SocketPool, _logger, this.configuration.UseSslStream);
5454
}
5555

5656
private void rezCallback(object state)

Enyim.Caching/Memcached/MemcachedNode.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ public class MemcachedNode : IMemcachedNode
3535
private bool isInitialized = false;
3636
private SemaphoreSlim poolInitSemaphore = new SemaphoreSlim(1, 1);
3737
private readonly TimeSpan _initPoolTimeout;
38+
private bool _useSslStream;
3839

3940
public MemcachedNode(
4041
EndPoint endpoint,
4142
ISocketPoolConfiguration socketPoolConfig,
42-
ILogger logger)
43+
ILogger logger,
44+
bool useSslStream)
4345
{
4446
_endPoint = endpoint;
47+
_useSslStream = useSslStream;
4548
EndPointString = endpoint?.ToString().Replace("Unspecified/", string.Empty);
4649
_config = socketPoolConfig;
4750

@@ -800,7 +803,7 @@ protected internal virtual PooledSocket CreateSocket()
800803
{
801804
try
802805
{
803-
var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger);
806+
var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream);
804807
ps.Connect();
805808
return ps;
806809
}
@@ -816,7 +819,7 @@ protected internal virtual async Task<PooledSocket> CreateSocketAsync()
816819
{
817820
try
818821
{
819-
var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger);
822+
var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream);
820823
await ps.ConnectAsync();
821824
return ps;
822825
}

Enyim.Caching/Memcached/PooledSocket.cs

Lines changed: 89 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.IO;
55
using System.Linq;
66
using System.Net;
7+
using System.Net.Security;
78
using System.Net.Sockets;
89
using System.Text;
910
using System.Threading;
@@ -18,16 +19,19 @@ public partial class PooledSocket : IDisposable
1819
private readonly ILogger _logger;
1920

2021
private bool _isAlive;
22+
private bool _useSslStream;
2123
private Socket _socket;
2224
private readonly EndPoint _endpoint;
2325
private readonly int _connectionTimeout;
2426

2527
private NetworkStream _inputStream;
28+
private SslStream _sslStream;
2629

27-
public PooledSocket(EndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, ILogger logger)
30+
public PooledSocket(EndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, ILogger logger, bool useSslStream)
2831
{
2932
_logger = logger;
3033
_isAlive = true;
34+
_useSslStream = useSslStream;
3135

3236
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
3337
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
@@ -90,7 +94,15 @@ void Cancel()
9094

9195
if (success)
9296
{
93-
_inputStream = new NetworkStream(_socket);
97+
if (_useSslStream)
98+
{
99+
_sslStream = new SslStream(new NetworkStream(_socket));
100+
_sslStream.AuthenticateAsClient(((DnsEndPoint)_endpoint).Host);
101+
}
102+
else
103+
{
104+
_inputStream = new NetworkStream(_socket);
105+
}
94106
}
95107
else
96108
{
@@ -141,7 +153,15 @@ public async Task ConnectAsync()
141153

142154
if (success)
143155
{
144-
_inputStream = new NetworkStream(_socket);
156+
if (_useSslStream)
157+
{
158+
_sslStream = new SslStream(new NetworkStream(_socket));
159+
await _sslStream.AuthenticateAsClientAsync(((DnsEndPoint)_endpoint).Host);
160+
}
161+
else
162+
{
163+
_inputStream = new NetworkStream(_socket);
164+
}
145165
}
146166
else
147167
{
@@ -251,7 +271,13 @@ protected void Dispose(bool disposing)
251271
_inputStream.Dispose();
252272
}
253273

274+
if (_sslStream != null)
275+
{
276+
_sslStream.Dispose();
277+
}
278+
254279
_inputStream = null;
280+
_sslStream = null;
255281
_socket = null;
256282
this.CleanupCallback = null;
257283
}
@@ -290,7 +316,7 @@ public int ReadByte()
290316

291317
try
292318
{
293-
return _inputStream.ReadByte();
319+
return (_useSslStream ? _sslStream.ReadByte() : _inputStream.ReadByte());
294320
}
295321
catch (Exception ex)
296322
{
@@ -309,7 +335,7 @@ public int ReadByteAsync()
309335

310336
try
311337
{
312-
return _inputStream.ReadByte();
338+
return (_useSslStream ? _sslStream.ReadByte() : _inputStream.ReadByte());
313339
}
314340
catch (Exception ex)
315341
{
@@ -332,7 +358,7 @@ public async Task ReadAsync(byte[] buffer, int offset, int count)
332358
{
333359
try
334360
{
335-
int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead);
361+
int currentRead = (_useSslStream ? await _sslStream.ReadAsync(buffer, offset, shouldRead) : await _inputStream.ReadAsync(buffer, offset, shouldRead));
336362
if (currentRead == count)
337363
break;
338364
if (currentRead < 1)
@@ -372,7 +398,7 @@ public void Read(byte[] buffer, int offset, int count)
372398
{
373399
try
374400
{
375-
int currentRead = _inputStream.Read(buffer, offset, shouldRead);
401+
int currentRead = (_useSslStream ? _sslStream.Read(buffer, offset, shouldRead) : _inputStream.Read(buffer, offset, shouldRead));
376402
if (currentRead == count)
377403
break;
378404
if (currentRead < 1)
@@ -397,15 +423,34 @@ public void Write(byte[] data, int offset, int length)
397423
{
398424
this.CheckDisposed();
399425

400-
SocketError status;
426+
if (_useSslStream)
427+
{
428+
try
429+
{
430+
_inputStream.Write(data, offset, length);
431+
_inputStream.Flush();
432+
}
433+
catch (Exception ex)
434+
{
435+
if (ex is IOException || ex is SocketException)
436+
{
437+
_isAlive = false;
438+
}
439+
throw;
440+
}
441+
}
442+
else
443+
{
444+
SocketError status;
401445

402-
_socket.Send(data, offset, length, SocketFlags.None, out status);
446+
_socket.Send(data, offset, length, SocketFlags.None, out status);
403447

404-
if (status != SocketError.Success)
405-
{
406-
_isAlive = false;
448+
if (status != SocketError.Success)
449+
{
450+
_isAlive = false;
407451

408-
ThrowHelper.ThrowSocketWriteError(_endpoint, status);
452+
ThrowHelper.ThrowSocketWriteError(_endpoint, status);
453+
}
409454
}
410455
}
411456

@@ -417,11 +462,22 @@ public void Write(IList<ArraySegment<byte>> buffers)
417462

418463
try
419464
{
420-
_socket.Send(buffers, SocketFlags.None, out status);
421-
if (status != SocketError.Success)
465+
if (_useSslStream)
422466
{
423-
_isAlive = false;
424-
ThrowHelper.ThrowSocketWriteError(_endpoint, status);
467+
foreach (var buf in buffers)
468+
{
469+
_sslStream.Write(buf.Array);
470+
}
471+
_sslStream.Flush();
472+
}
473+
else
474+
{
475+
_socket.Send(buffers, SocketFlags.None, out status);
476+
if (status != SocketError.Success)
477+
{
478+
_isAlive = false;
479+
ThrowHelper.ThrowSocketWriteError(_endpoint, status);
480+
}
425481
}
426482
}
427483
catch (Exception ex)
@@ -441,12 +497,23 @@ public async Task WriteAsync(IList<ArraySegment<byte>> buffers)
441497

442498
try
443499
{
444-
var bytesTransferred = await _socket.SendAsync(buffers, SocketFlags.None);
445-
if (bytesTransferred <= 0)
500+
if (_useSslStream)
446501
{
447-
_isAlive = false;
448-
_logger.LogError($"Failed to {nameof(PooledSocket.WriteAsync)}. bytesTransferred: {bytesTransferred}");
449-
ThrowHelper.ThrowSocketWriteError(_endpoint);
502+
foreach (var buf in buffers)
503+
{
504+
await _sslStream.WriteAsync(buf.Array,0,buf.Count);
505+
}
506+
await _sslStream.FlushAsync();
507+
}
508+
else
509+
{
510+
var bytesTransferred = await _socket.SendAsync(buffers, SocketFlags.None);
511+
if (bytesTransferred <= 0)
512+
{
513+
_isAlive = false;
514+
_logger.LogError($"Failed to {nameof(PooledSocket.WriteAsync)}. bytesTransferred: {bytesTransferred}");
515+
ThrowHelper.ThrowSocketWriteError(_endpoint);
516+
}
450517
}
451518
}
452519
catch (Exception ex)

Enyim.Caching/Memcached/Protocol/Binary/BinaryNode.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ public BinaryNode(
2323
EndPoint endpoint,
2424
ISocketPoolConfiguration config,
2525
ISaslAuthenticationProvider authenticationProvider,
26-
ILogger logger)
27-
: base(endpoint, config, logger)
26+
ILogger logger,
27+
bool useSslStream)
28+
: base(endpoint, config, logger, useSslStream)
2829
{
2930
this.authenticationProvider = authenticationProvider;
3031
_logger = logger;

Enyim.Caching/Memcached/Protocol/Binary/BinaryPool.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public BinaryPool(IMemcachedClientConfiguration configuration, ILogger logger)
2929

3030
protected override IMemcachedNode CreateNode(EndPoint endpoint)
3131
{
32-
return new BinaryNode(endpoint, this.configuration.SocketPool, this.authenticationProvider, _logger);
32+
return new BinaryNode(endpoint, this.configuration.SocketPool, this.authenticationProvider, _logger, this.configuration.UseSslStream);
3333
}
3434

3535
private static ISaslAuthenticationProvider GetProvider(IMemcachedClientConfiguration configuration)

0 commit comments

Comments
 (0)