diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index b602857563..59dd058406 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -261,6 +261,7 @@ + @@ -289,6 +290,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetCoreApp.cs new file mode 100644 index 0000000000..cb634cb6af --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetCoreApp.cs @@ -0,0 +1,305 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Buffers; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Data.SqlClient.SNI +{ + internal sealed partial class SslOverTdsStream + { + public override int Read(byte[] buffer, int offset, int count) + { + return Read(buffer.AsSpan(offset, count)); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Write(buffer.AsSpan(offset, count)); + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return ReadAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); + } + + public override int Read(Span buffer) + { + if (!_encapsulate) + { + return _stream.Read(buffer); + } + + using (SNIEventScope.Create(" reading encapsulated bytes")) + { + if (_packetBytes > 0) + { + // there are queued bytes from a previous packet available + // work out how many of the remaining bytes we can consume + int wantedCount = Math.Min(buffer.Length, _packetBytes); + int readCount = _stream.Read(buffer.Slice(0, wantedCount)); + if (readCount == 0) + { + // 0 means the connection was closed, tell the caller + return 0; + } + _packetBytes -= readCount; + return readCount; + } + else + { + Span headerBytes = stackalloc byte[TdsEnums.HEADER_LEN]; + + // fetch the packet header to determine how long the packet is + int headerBytesRead = 0; + do + { + int headerBytesReadIteration = _stream.Read(headerBytes.Slice(headerBytesRead, TdsEnums.HEADER_LEN - headerBytesRead)); + if (headerBytesReadIteration == 0) + { + // 0 means the connection was closed, tell the caller + return 0; + } + headerBytesRead += headerBytesReadIteration; + } while (headerBytesRead < TdsEnums.HEADER_LEN); + + // read the packet data size from the header and store it in case it is needed for a subsequent call + _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; + + // read as much from the packet as the caller can accept + int packetBytesRead = _stream.Read(buffer.Slice(0, Math.Min(buffer.Length, _packetBytes))); + _packetBytes -= packetBytesRead; + return packetBytesRead; + } + } + } + + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + if (!_encapsulate) + { + int read; + { + ValueTask readValueTask = _stream.ReadAsync(buffer, cancellationToken); + if (readValueTask.IsCompletedSuccessfully) + { + read = readValueTask.Result; + } + else + { + read = await readValueTask.ConfigureAwait(false); + } + } + return read; + } + using (SNIEventScope.Create(" reading encapsulated bytes")) + { + if (_packetBytes > 0) + { + // there are queued bytes from a previous packet available + // work out how many of the remaining bytes we can consume + int wantedCount = Math.Min(buffer.Length, _packetBytes); + + int readCount; + { + ValueTask remainderReadValueTask = _stream.ReadAsync(buffer.Slice(0, wantedCount), cancellationToken); + if (remainderReadValueTask.IsCompletedSuccessfully) + { + readCount = remainderReadValueTask.Result; + } + else + { + readCount = await remainderReadValueTask.ConfigureAwait(false); + } + } + if (readCount == 0) + { + // 0 means the connection was closed, tell the caller + return 0; + } + _packetBytes -= readCount; + return readCount; + } + else + { + byte[] headerBytes = ArrayPool.Shared.Rent(TdsEnums.HEADER_LEN); + + // fetch the packet header to determine how long the packet is + int headerBytesRead = 0; + do + { + int headerBytesReadIteration; + { + ValueTask headerReadValueTask = _stream.ReadAsync(headerBytes.AsMemory(headerBytesRead, (TdsEnums.HEADER_LEN - headerBytesRead)), cancellationToken); + if (headerReadValueTask.IsCompletedSuccessfully) + { + headerBytesReadIteration = headerReadValueTask.Result; + } + else + { + headerBytesReadIteration = await headerReadValueTask.ConfigureAwait(false); + } + } + if (headerBytesReadIteration == 0) + { + // 0 means the connection was closed, cleanup the rented array and then tell the caller + ArrayPool.Shared.Return(headerBytes, clearArray: true); + return 0; + } + headerBytesRead += headerBytesReadIteration; + } while (headerBytesRead < TdsEnums.HEADER_LEN); + + // read the packet data size from the header and store it in case it is needed for a subsequent call + _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; + + ArrayPool.Shared.Return(headerBytes, clearArray: true); + + // read as much from the packet as the caller can accept + int packetBytesRead; + { + ValueTask packetReadValueTask = _stream.ReadAsync(buffer.Slice(0, Math.Min(buffer.Length, _packetBytes)), cancellationToken); + if (packetReadValueTask.IsCompletedSuccessfully) + { + packetBytesRead = packetReadValueTask.Result; + } + else + { + packetBytesRead = await packetReadValueTask.ConfigureAwait(false); + } + } + _packetBytes -= packetBytesRead; + return packetBytesRead; + } + } + } + + public override void Write(ReadOnlySpan buffer) + { + // During the SSL negotiation phase, SSL is tunnelled over TDS packet type 0x12. After + // negotiation, the underlying socket only sees SSL frames. + if (!_encapsulate) + { + _stream.Write(buffer); + _stream.Flush(); + return; + } + + using (SNIEventScope.Create(" writing encapsulated bytes")) + { + ReadOnlySpan remaining = buffer; + byte[] packetBuffer = null; + try + { + while (remaining.Length > 0) + { + int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remaining.Length); + int packetLength = TdsEnums.HEADER_LEN + dataLength; + + if (packetBuffer == null) + { + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + else if (packetBuffer.Length < packetLength) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + + SetupPreLoginPacketHeader(packetBuffer, dataLength, remaining.Length - dataLength); + + Span data = packetBuffer.AsSpan(TdsEnums.HEADER_LEN, dataLength); + remaining.Slice(0, dataLength).CopyTo(data); + + _stream.Write(packetBuffer.AsSpan(0, packetLength)); + _stream.Flush(); + + remaining = remaining.Slice(dataLength); + } + } + finally + { + if (packetBuffer != null) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + } + } + } + } + + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + if (!_encapsulate) + { + { + ValueTask valueTask = _stream.WriteAsync(buffer, cancellationToken); + if (!valueTask.IsCompletedSuccessfully) + { + await valueTask.ConfigureAwait(false); + } + } + Task flushTask = _stream.FlushAsync(); + if (flushTask.IsCompletedSuccessfully) + { + await flushTask.ConfigureAwait(false); + } + return; + } + + using (SNIEventScope.Create(" writing encapsulated bytes")) + { + ReadOnlyMemory remaining = buffer; + byte[] packetBuffer = null; + try + { + while (remaining.Length > 0) + { + int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remaining.Length); + int packetLength = TdsEnums.HEADER_LEN + dataLength; + + if (packetBuffer == null) + { + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + else if (packetBuffer.Length < packetLength) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + + SetupPreLoginPacketHeader(packetBuffer, dataLength, remaining.Length - dataLength); + + remaining.Span.Slice(0, dataLength).CopyTo(packetBuffer.AsSpan(TdsEnums.HEADER_LEN, dataLength)); + + { + ValueTask packetWriteValueTask = _stream.WriteAsync(new ReadOnlyMemory(packetBuffer, 0, packetLength), cancellationToken); + if (!packetWriteValueTask.IsCompletedSuccessfully) + { + await packetWriteValueTask.ConfigureAwait(false); + } + } + + await _stream.FlushAsync().ConfigureAwait(false); + + + remaining = remaining.Slice(dataLength); + } + } + finally + { + if (packetBuffer != null) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + } + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs new file mode 100644 index 0000000000..7798b25d06 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs @@ -0,0 +1,224 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Buffers; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Data.SqlClient.SNI +{ + internal sealed partial class SslOverTdsStream : Stream + { + public override int Read(byte[] buffer, int offset, int count) + { + if (!_encapsulate) + { + return _stream.Read(buffer, offset, count); + } + + using (SNIEventScope.Create(" reading encapsulated bytes")) + { + if (_packetBytes > 0) + { + // there are queued bytes from a previous packet available + // work out how many of the remaining bytes we can consume + int wantedCount = Math.Min(count, _packetBytes); + int readCount = _stream.Read(buffer, offset, wantedCount); + if (readCount == 0) + { + // 0 means the connection was closed, tell the caller + return 0; + } + _packetBytes -= readCount; + return readCount; + } + else + { + byte[] headerBytes = ArrayPool.Shared.Rent(TdsEnums.HEADER_LEN); + Array.Clear(headerBytes, 0, headerBytes.Length); + + // fetch the packet header to determine how long the packet is + int headerBytesRead = 0; + do + { + int headerBytesReadIteration = _stream.Read(headerBytes, headerBytesRead, (TdsEnums.HEADER_LEN - headerBytesRead)); + if (headerBytesReadIteration == 0) + { + // 0 means the connection was closed, cleanup the rented array and then tell the caller + ArrayPool.Shared.Return(headerBytes, clearArray: true); + return 0; + } + headerBytesRead += headerBytesReadIteration; + } while (headerBytesRead < TdsEnums.HEADER_LEN); + + // read the packet data size from the header and store it in case it is needed for a subsequent call + _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; + + ArrayPool.Shared.Return(headerBytes, clearArray: true); + + // read as much from the packet as the caller can accept + int packetBytesRead = _stream.Read(buffer, offset, Math.Min(count, _packetBytes)); + _packetBytes -= packetBytesRead; + return packetBytesRead; + } + } + + } + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (!_encapsulate) + { + return await _stream.ReadAsync(buffer, offset, count, cancellationToken); + } + + using (SNIEventScope.Create(" reading encapsulated bytes")) + { + if (_packetBytes > 0) + { + // there are queued bytes from a previous packet available + // work out how many of the remaining bytes we can consume + int wantedCount = Math.Min(count, _packetBytes); + int readCount = await _stream.ReadAsync(buffer, offset, wantedCount, cancellationToken); + if (readCount == 0) + { + // 0 means the connection was closed, tell the caller + return 0; + } + _packetBytes -= readCount; + return readCount; + } + else + { + byte[] headerBytes = ArrayPool.Shared.Rent(TdsEnums.HEADER_LEN); + Array.Clear(headerBytes, 0, headerBytes.Length); + + // fetch the packet header to determine how long the packet is + int headerBytesRead = 0; + do + { + int headerBytesReadIteration = await _stream.ReadAsync(headerBytes, headerBytesRead, (TdsEnums.HEADER_LEN - headerBytesRead), cancellationToken); + if (headerBytesReadIteration == 0) + { + // 0 means the connection was closed, cleanup the rented array and then tell the caller + ArrayPool.Shared.Return(headerBytes, clearArray: true); + return 0; + } + headerBytesRead += headerBytesReadIteration; + } while (headerBytesRead < TdsEnums.HEADER_LEN); + + // read the packet data size from the header and store it in case it is needed for a subsequent call + _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; + + ArrayPool.Shared.Return(headerBytes, clearArray: true); + + // read as much from the packet as the caller can accept + int packetBytesRead = await _stream.ReadAsync(buffer, offset, Math.Min(count, _packetBytes), cancellationToken); + _packetBytes -= packetBytesRead; + return packetBytesRead; + } + } + } + + public override void Write(byte[] buffer, int offset, int count) + { + // During the SSL negotiation phase, SSL is tunnelled over TDS packet type 0x12. After + // negotiation, the underlying socket only sees SSL frames. + if (!_encapsulate) + { + _stream.Write(buffer, offset, count); + _stream.Flush(); + return; + } + + using (SNIEventScope.Create(" writing encapsulated bytes")) + { + int remainingBytes = count; + int dataOffset = offset; + byte[] packetBuffer = null; + while (remainingBytes > 0) + { + int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remainingBytes); + int packetLength = TdsEnums.HEADER_LEN + dataLength; + remainingBytes -= dataLength; + + if (packetBuffer == null) + { + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + else if (packetBuffer.Length < packetLength) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + + SetupPreLoginPacketHeader(packetBuffer, dataLength, remainingBytes); + + Array.Copy(buffer, dataOffset, packetBuffer, TdsEnums.HEADER_LEN, dataLength); + + _stream.Write(packetBuffer, 0, packetLength); + _stream.Flush(); + + dataOffset += dataLength; + } + if (packetBuffer != null) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + } + } + } + + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (!_encapsulate) + { + await _stream.WriteAsync(buffer, offset, count).ConfigureAwait(false); + Task flushTask = _stream.FlushAsync(); + if (flushTask.Status == TaskStatus.RanToCompletion) + { + await flushTask.ConfigureAwait(false); + } + return; + } + + using (SNIEventScope.Create(" writing encapsulated bytes")) + { + int remainingBytes = count; + int dataOffset = offset; + byte[] packetBuffer = null; + while (remainingBytes > 0) + { + int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remainingBytes); + int packetLength = TdsEnums.HEADER_LEN + dataLength; + remainingBytes -= dataLength; + + if (packetBuffer == null) + { + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + else if (packetBuffer.Length < packetLength) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + packetBuffer = ArrayPool.Shared.Rent(packetLength); + } + + SetupPreLoginPacketHeader(packetBuffer, dataLength, remainingBytes); + + Array.Copy(buffer, dataOffset, packetBuffer, TdsEnums.HEADER_LEN, dataLength); + + await _stream.WriteAsync(packetBuffer, 0, packetLength, cancellationToken).ConfigureAwait(false); + await _stream.FlushAsync().ConfigureAwait(false); + + dataOffset += dataLength; + } + if (packetBuffer != null) + { + ArrayPool.Shared.Return(packetBuffer, clearArray: true); + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.cs index 74a2e6226d..58384dfd58 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.cs @@ -3,11 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Buffers; using System.IO; using System.IO.Pipes; -using System.Threading; -using System.Threading.Tasks; namespace Microsoft.Data.SqlClient.SNI { @@ -16,7 +13,7 @@ namespace Microsoft.Data.SqlClient.SNI /// transported in TDS packet type 0x12. Once SSL handshake has completed, SSL /// packets are sent transparently. /// - internal sealed class SslOverTdsStream : Stream + internal sealed partial class SslOverTdsStream : Stream { private readonly Stream _stream; @@ -42,197 +39,14 @@ public SslOverTdsStream(Stream stream) public void FinishHandshake() { _encapsulate = false; - } - - /// - /// Read buffer - /// - /// Buffer - /// Offset - /// Byte count - /// Bytes read - public override int Read(byte[] buffer, int offset, int count) => - ReadInternal(buffer, offset, count, CancellationToken.None, async: false).GetAwaiter().GetResult(); - - /// - /// Write Buffer - /// - /// - /// - /// - public override void Write(byte[] buffer, int offset, int count) - => WriteInternal(buffer, offset, count, CancellationToken.None, async: false).Wait(); - - /// - /// Write Buffer Asynchronously - /// - /// - /// - /// - /// - /// - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token) - => WriteInternal(buffer, offset, count, token, async: true); - - /// - /// Read Buffer Asynchronously - /// - /// - /// - /// - /// - /// - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) - => ReadInternal(buffer, offset, count, token, async: true); - - /// - /// Read Internal is called synchronously when async is false - /// - private async Task ReadInternal(byte[] buffer, int offset, int count, CancellationToken token, bool async) - { - int readBytes = 0; - byte[] packetData = null; - byte[] readTarget = buffer; - int readOffset = offset; - if (_encapsulate) - { - packetData = ArrayPool.Shared.Rent(count < TdsEnums.HEADER_LEN ? TdsEnums.HEADER_LEN : count); - readTarget = packetData; - readOffset = 0; - if (_packetBytes == 0) - { - // Account for split packets - while (readBytes < TdsEnums.HEADER_LEN) - { - var readBytesForHeader = async ? - await _stream.ReadAsync(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes, token).ConfigureAwait(false) : - _stream.Read(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes); - - if (readBytesForHeader == 0) - { - throw new EndOfStreamException("End of stream reached"); - } - - readBytes += readBytesForHeader; - } - - _packetBytes = (packetData[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | packetData[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]; - _packetBytes -= TdsEnums.HEADER_LEN; - } - - if (count > _packetBytes) - { - count = _packetBytes; - } - } - - readBytes = async ? - await _stream.ReadAsync(readTarget, readOffset, count, token).ConfigureAwait(false) : - _stream.Read(readTarget, readOffset, count); - - if (_encapsulate) - { - _packetBytes -= readBytes; - } - if (packetData != null) - { - Buffer.BlockCopy(packetData, 0, buffer, offset, readBytes); - ArrayPool.Shared.Return(packetData, clearArray: true); - } - return readBytes; - } - - /// - /// The internal write method calls Sync APIs when Async flag is false - /// - private async Task WriteInternal(byte[] buffer, int offset, int count, CancellationToken token, bool async) - { - int currentCount = 0; - int currentOffset = offset; - - while (count > 0) - { - // During the SSL negotiation phase, SSL is tunneled over TDS packet type 0x12. After - // negotiation, the underlying socket only sees SSL frames. - // - if (_encapsulate) - { - if (count > PACKET_SIZE_WITHOUT_HEADER) - { - currentCount = PACKET_SIZE_WITHOUT_HEADER; - } - else - { - currentCount = count; - } - - count -= currentCount; - - // Prepend buffer data with TDS prelogin header - int combinedLength = TdsEnums.HEADER_LEN + currentCount; - byte[] combinedBuffer = ArrayPool.Shared.Rent(combinedLength); - - // We can only send 4088 bytes in one packet. Header[1] is set to 1 if this is a - // partial packet (whether or not count != 0). - combinedBuffer[7] = 0; // touch this first for the jit bounds check - combinedBuffer[0] = PRELOGIN_PACKET_TYPE; - combinedBuffer[1] = (byte)(count > 0 ? 0 : 1); - combinedBuffer[2] = (byte)((currentCount + TdsEnums.HEADER_LEN) / 0x100); - combinedBuffer[3] = (byte)((currentCount + TdsEnums.HEADER_LEN) % 0x100); - combinedBuffer[4] = 0; - combinedBuffer[5] = 0; - combinedBuffer[6] = 0; - - Array.Copy(buffer, currentOffset, combinedBuffer, TdsEnums.HEADER_LEN, (combinedLength - TdsEnums.HEADER_LEN)); - - if (async) - { - await _stream.WriteAsync(combinedBuffer, 0, combinedLength, token).ConfigureAwait(false); - } - else - { - _stream.Write(combinedBuffer, 0, combinedLength); - } - - Array.Clear(combinedBuffer, 0, combinedLength); - ArrayPool.Shared.Return(combinedBuffer); - } - else - { - currentCount = count; - count = 0; - - if (async) - { - await _stream.WriteAsync(buffer, currentOffset, currentCount, token).ConfigureAwait(false); - } - else - { - _stream.Write(buffer, currentOffset, currentCount); - } - } - - if (async) - { - await _stream.FlushAsync().ConfigureAwait(false); - } - else - { - _stream.Flush(); - } - - currentOffset += currentCount; - } + SqlClientEventSource.Log.TrySNITraceEvent(" switched from encapsulation to passthrough mode"); } /// /// Set stream length. /// /// Length - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); /// /// Flush stream @@ -252,14 +66,8 @@ public override void Flush() /// public override long Position { - get - { - throw new NotSupportedException(); - } - set - { - throw new NotSupportedException(); - } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); } /// @@ -268,44 +76,40 @@ public override long Position /// Offset /// Origin /// Position - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); /// /// Check if stream can be read from /// - public override bool CanRead - { - get { return _stream.CanRead; } - } + public override bool CanRead => _stream.CanRead; /// /// Check if stream can be written to /// - public override bool CanWrite - { - get { return _stream.CanWrite; } - } + public override bool CanWrite => _stream.CanWrite; /// /// Check if stream can be seeked /// - public override bool CanSeek - { - get { return false; } // Seek not supported - } + public override bool CanSeek => false; /// /// Get stream length /// - public override long Length + public override long Length => throw new NotSupportedException(); + + private static void SetupPreLoginPacketHeader(byte[] buffer, int dataLength, int remainingLength) { - get - { - throw new NotSupportedException(); - } + // We can only send 4088 bytes in one packet. Header[1] is set to 1 if this is a + // partial packet (whether or not count != 0). + buffer[7] = 0; // touch this first for the jit bounds check + buffer[0] = PRELOGIN_PACKET_TYPE; + buffer[1] = (byte)(remainingLength > 0 ? 0 : 1); + buffer[2] = (byte)((dataLength + TdsEnums.HEADER_LEN) / 0x100); + buffer[3] = (byte)((dataLength + TdsEnums.HEADER_LEN) % 0x100); + buffer[4] = 0; + buffer[5] = 0; + buffer[6] = 0; } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index a2d49e96c8..d7f0decbf5 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Diagnostics.Tracing; using System.Threading; @@ -1011,4 +1012,24 @@ internal void SNIScopeLeave(long scopeId) } #endregion } + + internal readonly struct SNIEventScope : IDisposable + { + private readonly long _scopeID; + + public SNIEventScope(long scopeID) + { + _scopeID = scopeID; + } + + public void Dispose() + { + SqlClientEventSource.Log.SNIScopeLeave(_scopeID); + } + + public static SNIEventScope Create(string message) + { + return new SNIEventScope(SqlClientEventSource.Log.SNIScopeEnter(message)); + } + } }