diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 000000000..3b0b4239d --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/after.DotNetty.sln.targets b/after.DotNetty.sln.targets new file mode 100644 index 000000000..0c0fbc6ae --- /dev/null +++ b/after.DotNetty.sln.targets @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/DotNetty.Buffers/IByteBufferAllocatorMetric .cs b/src/DotNetty.Buffers/IByteBufferAllocatorMetric.cs similarity index 100% rename from src/DotNetty.Buffers/IByteBufferAllocatorMetric .cs rename to src/DotNetty.Buffers/IByteBufferAllocatorMetric.cs diff --git a/src/DotNetty.Codecs.Http/Multipart/IHttpData .cs b/src/DotNetty.Codecs.Http/Multipart/IHttpData.cs similarity index 100% rename from src/DotNetty.Codecs.Http/Multipart/IHttpData .cs rename to src/DotNetty.Codecs.Http/Multipart/IHttpData.cs diff --git a/src/DotNetty.Codecs.Redis/Messages/DefaultBulkStringRedisContent .cs b/src/DotNetty.Codecs.Redis/Messages/DefaultBulkStringRedisContent.cs similarity index 100% rename from src/DotNetty.Codecs.Redis/Messages/DefaultBulkStringRedisContent .cs rename to src/DotNetty.Codecs.Redis/Messages/DefaultBulkStringRedisContent.cs diff --git a/src/DotNetty.Codecs/ByteToMessageDecoder.cs b/src/DotNetty.Codecs/ByteToMessageDecoder.cs index 1a04bd423..72ef98ca9 100644 --- a/src/DotNetty.Codecs/ByteToMessageDecoder.cs +++ b/src/DotNetty.Codecs/ByteToMessageDecoder.cs @@ -249,7 +249,7 @@ protected void DiscardSomeReadBytes() // See: // - https://github.com/netty/netty/issues/2327 // - https://github.com/netty/netty/issues/1764 - this.cumulation.DiscardReadBytes(); // todo: use discardSomeReadBytes + this.cumulation.DiscardSomeReadBytes(); } } diff --git a/src/DotNetty.Handlers/Logging/LoggingHandler.cs b/src/DotNetty.Handlers/Logging/LoggingHandler.cs index eaf2e245c..1115d1f41 100644 --- a/src/DotNetty.Handlers/Logging/LoggingHandler.cs +++ b/src/DotNetty.Handlers/Logging/LoggingHandler.cs @@ -209,6 +209,48 @@ public override void ChannelRead(IChannelHandlerContext ctx, object message) ctx.FireChannelRead(message); } + public override void ChannelReadComplete(IChannelHandlerContext ctx) + { + if (this.Logger.IsEnabled(this.InternalLevel)) + { + this.Logger.Log(this.InternalLevel, this.Format(ctx, "RECEIVED_COMPLETE")); + } + ctx.FireChannelReadComplete(); + } + + public override void ChannelWritabilityChanged(IChannelHandlerContext ctx) + { + if (this.Logger.IsEnabled(this.InternalLevel)) + { + this.Logger.Log(this.InternalLevel, this.Format(ctx, "WRITABILITY", ctx.Channel.IsWritable)); + } + ctx.FireChannelWritabilityChanged(); + } + + public override void HandlerAdded(IChannelHandlerContext ctx) + { + if (this.Logger.IsEnabled(this.InternalLevel)) + { + this.Logger.Log(this.InternalLevel, this.Format(ctx, "HANDLER_ADDED")); + } + } + public override void HandlerRemoved(IChannelHandlerContext ctx) + { + if (this.Logger.IsEnabled(this.InternalLevel)) + { + this.Logger.Log(this.InternalLevel, this.Format(ctx, "HANDLER_REMOVED")); + } + } + + public override void Read(IChannelHandlerContext ctx) + { + if (this.Logger.IsEnabled(this.InternalLevel)) + { + this.Logger.Log(this.InternalLevel, this.Format(ctx, "READ")); + } + ctx.Read(); + } + public override Task WriteAsync(IChannelHandlerContext ctx, object msg) { if (this.Logger.IsEnabled(this.InternalLevel)) diff --git a/src/DotNetty.Handlers/Tls/SniHandler.cs b/src/DotNetty.Handlers/Tls/SniHandler.cs index 8a797a119..0e2bb8276 100644 --- a/src/DotNetty.Handlers/Tls/SniHandler.cs +++ b/src/DotNetty.Handlers/Tls/SniHandler.cs @@ -28,7 +28,7 @@ public sealed class SniHandler : ByteToMessageDecoder bool readPending; public SniHandler(ServerTlsSniSettings settings) - : this(stream => new SslStream(stream, false), settings) + : this(stream => new SslStream(stream, true), settings) { } diff --git a/src/DotNetty.Handlers/Tls/TlsHandler.cs b/src/DotNetty.Handlers/Tls/TlsHandler.cs index d58684ac8..063aa2db9 100644 --- a/src/DotNetty.Handlers/Tls/TlsHandler.cs +++ b/src/DotNetty.Handlers/Tls/TlsHandler.cs @@ -5,6 +5,7 @@ namespace DotNetty.Handlers.Tls { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Diagnostics.Contracts; using System.IO; using System.Net.Security; @@ -41,7 +42,7 @@ public sealed class TlsHandler : ByteToMessageDecoder Task pendingSslStreamReadFuture; public TlsHandler(TlsSettings settings) - : this(stream => new SslStream(stream, false), settings) + : this(stream => new SslStream(stream, true), settings) { } @@ -69,8 +70,6 @@ public TlsHandler(Func sslStreamFactory, TlsSettings settings bool IsServer => this.settings is ServerTlsSettings; - public void Dispose() => this.sslStream?.Dispose(); - public override void ChannelActive(IChannelHandlerContext context) { base.ChannelActive(context); @@ -344,6 +343,9 @@ void Unwrap(IChannelHandlerContext ctx, IByteBuffer packet, int offset, int leng outputBuffer = this.pendingSslStreamReadBuffer; outputBufferLength = outputBuffer.WritableBytes; + + this.pendingSslStreamReadFuture = null; + this.pendingSslStreamReadBuffer = null; } else { @@ -363,17 +365,23 @@ void Unwrap(IChannelHandlerContext ctx, IByteBuffer packet, int offset, int leng if (!currentReadFuture.IsCompleted) { // we did feed the whole current packet to SslStream yet it did not produce any result -> move to the next packet in input - Contract.Assert(this.mediationStream.SourceReadableBytes == 0); continue; } int read = currentReadFuture.Result; + if (read == 0) + { + //Stream closed + return; + } + // Now output the result of previous read and decide whether to do an extra read on the same source or move forward AddBufferToOutput(outputBuffer, read, output); currentReadFuture = null; + outputBuffer = null; if (this.mediationStream.SourceReadableBytes == 0) { // we just made a frame available for reading but there was already pending read so SslStream read it out to make further progress there @@ -620,6 +628,7 @@ void HandleFailure(Exception cause) // Release all resources such as internal buffers that SSLEngine // is managing. + this.mediationStream.Dispose(); try { this.sslStream.Dispose(); @@ -701,14 +710,13 @@ public void ExpandSource(int count) this.inputLength += count; - TaskCompletionSource promise = this.readCompletionSource; - if (promise == null) + ArraySegment sslBuffer = this.sslOwnedBuffer; + if (sslBuffer.Array == null) { // there is no pending read operation - keep for future return; } - - ArraySegment sslBuffer = this.sslOwnedBuffer; + this.sslOwnedBuffer = default(ArraySegment); #if NETSTANDARD1_3 this.readByteCount = this.ReadFromInput(sslBuffer.Array, sslBuffer.Offset, sslBuffer.Count); @@ -718,29 +726,35 @@ public void ExpandSource(int count) { var self = (MediationStream)ms; TaskCompletionSource p = self.readCompletionSource; - this.readCompletionSource = null; + self.readCompletionSource = null; p.TrySetResult(self.readByteCount); }, this) .RunSynchronously(TaskScheduler.Default); #else int read = this.ReadFromInput(sslBuffer.Array, sslBuffer.Offset, sslBuffer.Count); + + TaskCompletionSource promise = this.readCompletionSource; this.readCompletionSource = null; promise.TrySetResult(read); - this.readCallback?.Invoke(promise.Task); + + AsyncCallback callback = this.readCallback; + this.readCallback = null; + callback?.Invoke(promise.Task); #endif } #if NETSTANDARD1_3 public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (this.inputLength - this.inputOffset > 0) + if (this.SourceReadableBytes > 0) { // we have the bytes available upfront - write out synchronously int read = this.ReadFromInput(buffer, offset, count); return Task.FromResult(read); } + Contract.Assert(this.sslOwnedBuffer.Array == null); // take note of buffer - we will pass bytes there once available this.sslOwnedBuffer = new ArraySegment(buffer, offset, count); this.readCompletionSource = new TaskCompletionSource(); @@ -749,13 +763,16 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel #else public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { - if (this.inputLength - this.inputOffset > 0) + if (this.SourceReadableBytes > 0) { // we have the bytes available upfront - write out synchronously int read = this.ReadFromInput(buffer, offset, count); - return this.PrepareSyncReadResult(read, state); + var res = this.PrepareSyncReadResult(read, state); + callback?.Invoke(res); + return res; } + Contract.Assert(this.sslOwnedBuffer.Array == null); // take note of buffer - we will pass bytes there once available this.sslOwnedBuffer = new ArraySegment(buffer, offset, count); this.readCompletionSource = new TaskCompletionSource(state); @@ -771,6 +788,7 @@ public override int EndRead(IAsyncResult asyncResult) return syncResult.Result; } + Debug.Assert(this.readCompletionSource == null || this.readCompletionSource.Task == asyncResult); Contract.Assert(!((Task)asyncResult).IsCanceled); try @@ -782,12 +800,6 @@ public override int EndRead(IAsyncResult asyncResult) ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); throw; // unreachable } - finally - { - this.readCompletionSource = null; - this.readCallback = null; - this.sslOwnedBuffer = default(ArraySegment); - } } IAsyncResult PrepareSyncReadResult(int readBytes, object state) @@ -817,43 +829,55 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As // write+flush completed synchronously (and successfully) var result = new SynchronousAsyncResult(); result.AsyncState = state; - callback(result); + callback?.Invoke(result); return result; default: - this.writeCallback = callback; - var tcs = new TaskCompletionSource(state); - this.writeCompletion = tcs; - task.ContinueWith(WriteCompleteCallback, this, TaskContinuationOptions.ExecuteSynchronously); - return tcs.Task; + if (callback != null || state != task.AsyncState) + { + Contract.Assert(this.writeCompletion == null); + this.writeCallback = callback; + var tcs = new TaskCompletionSource(state); + this.writeCompletion = tcs; + task.ContinueWith(WriteCompleteCallback, this, TaskContinuationOptions.ExecuteSynchronously); + return tcs.Task; + } + else + { + return task; + } } } static void HandleChannelWriteComplete(Task writeTask, object state) { var self = (MediationStream)state; + + AsyncCallback callback = self.writeCallback; + self.writeCallback = null; + + var promise = self.writeCompletion; + self.writeCompletion = null; + switch (writeTask.Status) { case TaskStatus.RanToCompletion: - self.writeCompletion.TryComplete(); + promise.TryComplete(); break; case TaskStatus.Canceled: - self.writeCompletion.TrySetCanceled(); + promise.TrySetCanceled(); break; case TaskStatus.Faulted: - self.writeCompletion.TrySetException(writeTask.Exception); + promise.TrySetException(writeTask.Exception); break; default: throw new ArgumentOutOfRangeException("Unexpected task status: " + writeTask.Status); } - self.writeCallback?.Invoke(self.writeCompletion.Task); + callback?.Invoke(promise.Task); } public override void EndWrite(IAsyncResult asyncResult) { - this.writeCallback = null; - this.writeCompletion = null; - if (asyncResult is SynchronousAsyncResult) { return; @@ -861,7 +885,7 @@ public override void EndWrite(IAsyncResult asyncResult) try { - ((Task)asyncResult).Wait(); + ((Task)asyncResult).Wait(); } catch (AggregateException ex) { @@ -876,7 +900,7 @@ int ReadFromInput(byte[] destination, int destinationOffset, int destinationCapa Contract.Assert(destination != null); byte[] source = this.input; - int readableBytes = this.inputLength - this.inputOffset; + int readableBytes = this.SourceReadableBytes; int length = Math.Min(readableBytes, destinationCapacity); Buffer.BlockCopy(source, this.inputStartOffset + this.inputOffset, destination, destinationOffset, length); this.inputOffset += length; @@ -894,8 +918,11 @@ protected override void Dispose(bool disposing) if (disposing) { TaskCompletionSource p = this.readCompletionSource; - this.readCompletionSource = null; - p?.TrySetResult(0); + if (p != null) + { + this.readCompletionSource = null; + p.TrySetResult(0); + } } } diff --git a/src/DotNetty.Transport/Channels/Sockets/TcpServerSocketChannel.cs b/src/DotNetty.Transport/Channels/Sockets/TcpServerSocketChannel.cs index a5409e1c8..6209bfded 100644 --- a/src/DotNetty.Transport/Channels/Sockets/TcpServerSocketChannel.cs +++ b/src/DotNetty.Transport/Channels/Sockets/TcpServerSocketChannel.cs @@ -16,7 +16,7 @@ namespace DotNetty.Transport.Channels.Sockets public class TcpServerSocketChannel : AbstractSocketChannel, IServerSocketChannel { static readonly IInternalLogger Logger = InternalLoggerFactory.GetInstance(); - static readonly ChannelMetadata METADATA = new ChannelMetadata(false, 16); + static readonly ChannelMetadata METADATA = new ChannelMetadata(false); static readonly Action ReadCompletedSyncCallback = OnReadCompletedSync; diff --git a/test/DotNetty.Buffers.Tests/DotNetty.Buffers.Tests.csproj b/test/DotNetty.Buffers.Tests/DotNetty.Buffers.Tests.csproj index 6986327ee..838f0f183 100644 --- a/test/DotNetty.Buffers.Tests/DotNetty.Buffers.Tests.csproj +++ b/test/DotNetty.Buffers.Tests/DotNetty.Buffers.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Codecs.Http.Tests/DotNetty.Codecs.Http.Tests.csproj b/test/DotNetty.Codecs.Http.Tests/DotNetty.Codecs.Http.Tests.csproj index b15ef7373..68cb33eb0 100644 --- a/test/DotNetty.Codecs.Http.Tests/DotNetty.Codecs.Http.Tests.csproj +++ b/test/DotNetty.Codecs.Http.Tests/DotNetty.Codecs.Http.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Codecs.Mqtt.Tests/DotNetty.Codecs.Mqtt.Tests.csproj b/test/DotNetty.Codecs.Mqtt.Tests/DotNetty.Codecs.Mqtt.Tests.csproj index aef3c242d..94a2c5373 100644 --- a/test/DotNetty.Codecs.Mqtt.Tests/DotNetty.Codecs.Mqtt.Tests.csproj +++ b/test/DotNetty.Codecs.Mqtt.Tests/DotNetty.Codecs.Mqtt.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Codecs.Protobuf.Tests/DotNetty.Codecs.Protobuf.Tests.csproj b/test/DotNetty.Codecs.Protobuf.Tests/DotNetty.Codecs.Protobuf.Tests.csproj index d05f4d68a..fbda200fe 100644 --- a/test/DotNetty.Codecs.Protobuf.Tests/DotNetty.Codecs.Protobuf.Tests.csproj +++ b/test/DotNetty.Codecs.Protobuf.Tests/DotNetty.Codecs.Protobuf.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Codecs.ProtocolBuffers.Tests/DotNetty.Codecs.ProtocolBuffers.Tests.csproj b/test/DotNetty.Codecs.ProtocolBuffers.Tests/DotNetty.Codecs.ProtocolBuffers.Tests.csproj index 930b7fdcd..80b7207f9 100644 --- a/test/DotNetty.Codecs.ProtocolBuffers.Tests/DotNetty.Codecs.ProtocolBuffers.Tests.csproj +++ b/test/DotNetty.Codecs.ProtocolBuffers.Tests/DotNetty.Codecs.ProtocolBuffers.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/test/DotNetty.Codecs.Redis.Tests/DotNetty.Codecs.Redis.Tests.csproj b/test/DotNetty.Codecs.Redis.Tests/DotNetty.Codecs.Redis.Tests.csproj index b1d279c4e..79fe90538 100644 --- a/test/DotNetty.Codecs.Redis.Tests/DotNetty.Codecs.Redis.Tests.csproj +++ b/test/DotNetty.Codecs.Redis.Tests/DotNetty.Codecs.Redis.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Codecs.Tests/DotNetty.Codecs.Tests.csproj b/test/DotNetty.Codecs.Tests/DotNetty.Codecs.Tests.csproj index 8611de169..5a857c12a 100644 --- a/test/DotNetty.Codecs.Tests/DotNetty.Codecs.Tests.csproj +++ b/test/DotNetty.Codecs.Tests/DotNetty.Codecs.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Common.Tests/DotNetty.Common.Tests.csproj b/test/DotNetty.Common.Tests/DotNetty.Common.Tests.csproj index 41f874004..3072c517e 100644 --- a/test/DotNetty.Common.Tests/DotNetty.Common.Tests.csproj +++ b/test/DotNetty.Common.Tests/DotNetty.Common.Tests.csproj @@ -8,11 +8,10 @@ - + - diff --git a/test/DotNetty.Common.Tests/Internal/Logging/InternalLoggerFactoryTest.cs b/test/DotNetty.Common.Tests/Internal/Logging/InternalLoggerFactoryTest.cs index 11166aeff..67234facb 100644 --- a/test/DotNetty.Common.Tests/Internal/Logging/InternalLoggerFactoryTest.cs +++ b/test/DotNetty.Common.Tests/Internal/Logging/InternalLoggerFactoryTest.cs @@ -10,6 +10,7 @@ namespace DotNetty.Common.Tests.Internal.Logging using Moq; using Xunit; + [CollectionDefinition(nameof(InternalLoggerFactoryTest), DisableParallelization = true)] public class InternalLoggerFactoryTest { // todo: CodeContracts on CI diff --git a/test/DotNetty.Handlers.Tests/DotNetty.Handlers.Tests.csproj b/test/DotNetty.Handlers.Tests/DotNetty.Handlers.Tests.csproj index 40e97f62a..538e02e9d 100644 --- a/test/DotNetty.Handlers.Tests/DotNetty.Handlers.Tests.csproj +++ b/test/DotNetty.Handlers.Tests/DotNetty.Handlers.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Handlers.Tests/TlsHandlerTest.cs b/test/DotNetty.Handlers.Tests/TlsHandlerTest.cs index b138b7697..ba7748c59 100644 --- a/test/DotNetty.Handlers.Tests/TlsHandlerTest.cs +++ b/test/DotNetty.Handlers.Tests/TlsHandlerTest.cs @@ -102,7 +102,11 @@ public async Task TlsRead(int[] frameLengths, bool isClient, IWriteStrategy writ await Task.WhenAll(writeTasks).WithTimeout(TimeSpan.FromSeconds(5)); IByteBuffer finalReadBuffer = Unpooled.Buffer(16 * 1024); await ReadOutboundAsync(async () => ch.ReadInbound(), expectedBuffer.ReadableBytes, finalReadBuffer, TestTimeout); - Assert.True(ByteBufferUtil.Equals(expectedBuffer, finalReadBuffer), $"---Expected:\n{ByteBufferUtil.PrettyHexDump(expectedBuffer)}\n---Actual:\n{ByteBufferUtil.PrettyHexDump(finalReadBuffer)}"); + bool isEqual = ByteBufferUtil.Equals(expectedBuffer, finalReadBuffer); + if (!isEqual) + { + Assert.True(isEqual, $"---Expected:\n{ByteBufferUtil.PrettyHexDump(expectedBuffer)}\n---Actual:\n{ByteBufferUtil.PrettyHexDump(finalReadBuffer)}"); + } driverStream.Dispose(); Assert.False(ch.Finish()); } @@ -188,7 +192,11 @@ await ReadOutboundAsync( return Unpooled.WrappedBuffer(readBuffer, 0, read); }, expectedBuffer.ReadableBytes, finalReadBuffer, TestTimeout); - Assert.True(ByteBufferUtil.Equals(expectedBuffer, finalReadBuffer), $"---Expected:\n{ByteBufferUtil.PrettyHexDump(expectedBuffer)}\n---Actual:\n{ByteBufferUtil.PrettyHexDump(finalReadBuffer)}"); + bool isEqual = ByteBufferUtil.Equals(expectedBuffer, finalReadBuffer); + if (!isEqual) + { + Assert.True(isEqual, $"---Expected:\n{ByteBufferUtil.PrettyHexDump(expectedBuffer)}\n---Actual:\n{ByteBufferUtil.PrettyHexDump(finalReadBuffer)}"); + } driverStream.Dispose(); Assert.False(ch.Finish()); } diff --git a/test/DotNetty.Tests.Common/DotNetty.Tests.Common.csproj b/test/DotNetty.Tests.Common/DotNetty.Tests.Common.csproj index 035d6f1b3..bd65f7d97 100644 --- a/test/DotNetty.Tests.Common/DotNetty.Tests.Common.csproj +++ b/test/DotNetty.Tests.Common/DotNetty.Tests.Common.csproj @@ -12,7 +12,7 @@ - + diff --git a/test/DotNetty.Tests.End2End/DotNetty.Tests.End2End.csproj b/test/DotNetty.Tests.End2End/DotNetty.Tests.End2End.csproj index bd34b7cd2..97b3df236 100644 --- a/test/DotNetty.Tests.End2End/DotNetty.Tests.End2End.csproj +++ b/test/DotNetty.Tests.End2End/DotNetty.Tests.End2End.csproj @@ -8,7 +8,7 @@ - + diff --git a/test/DotNetty.Transport.Libuv.Tests/DotNetty.Transport.Libuv.Tests.csproj b/test/DotNetty.Transport.Libuv.Tests/DotNetty.Transport.Libuv.Tests.csproj index fcb22d1b4..ae693fde1 100644 --- a/test/DotNetty.Transport.Libuv.Tests/DotNetty.Transport.Libuv.Tests.csproj +++ b/test/DotNetty.Transport.Libuv.Tests/DotNetty.Transport.Libuv.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/DotNetty.Transport.Tests/DotNetty.Transport.Tests.csproj b/test/DotNetty.Transport.Tests/DotNetty.Transport.Tests.csproj index b4d81eb10..84618c05f 100644 --- a/test/DotNetty.Transport.Tests/DotNetty.Transport.Tests.csproj +++ b/test/DotNetty.Transport.Tests/DotNetty.Transport.Tests.csproj @@ -8,7 +8,7 @@ - +