<commit_before>// 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.Buffers;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;

namespace System.Data.SqlClient.SNI
{
    /// <summary>
    /// SSL encapsulated over TDS transport. During SSL handshake, SSL packets are
    /// transported in TDS packet type 0x12. Once SSL handshake has completed, SSL
    /// packets are sent transparently.
    /// </summary>
    internal sealed class SslOverTdsStream : Stream
    {
        private readonly Stream _stream;

        private int _packetBytes = 0;
        private bool _encapsulate;

        private const int PACKET_SIZE_WITHOUT_HEADER = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE - TdsEnums.HEADER_LEN;
        private const int PRELOGIN_PACKET_TYPE = 0x12;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="stream">Underlying stream</param>
        public SslOverTdsStream(Stream stream)
        {
            _stream = stream;
            _encapsulate = true;
        }

        /// <summary>
        /// Finish SSL handshake. Stop encapsulating in TDS.
        /// </summary>
        public void FinishHandshake()
        {
            _encapsulate = false;
        }

        /// <summary>
        /// Read buffer
        /// </summary>
        /// <param name="buffer">Buffer</param>
        /// <param name="offset">Offset</param>
        /// <param name="count">Byte count</param>
        /// <returns>Bytes read</returns>
        public override int Read(byte[] buffer, int offset, int count) =>
            ReadInternal(buffer, offset, count, CancellationToken.None, async: false).GetAwaiter().GetResult();

        /// <summary>
        /// Write Buffer
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public override void Write(byte[] buffer, int offset, int count)
            => WriteInternal(buffer, offset, count, CancellationToken.None, async: false).Wait();

        /// <summary>
        /// Write Buffer Asynchronosly
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
            => WriteInternal(buffer, offset, count, token, async: true);

        /// <summary>
        /// Read Buffer Asynchronosly
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token)
            => ReadInternal(buffer, offset, count, token, async: true);

        /// <summary>
        /// Read Internal is called synchronosly when async is false
        /// </summary>
        private async Task<int> ReadInternal(byte[] buffer, int offset, int count, CancellationToken token, bool async)
        {
            if (_encapsulate)
            {
                return await ReadInternalEncapsulate(buffer, offset, count, token, async);
            }
            else if (async)
            {
                return await ReadInternalAsync(buffer, offset, count, token);
            }
            else
            {
                return ReadInternalSync(buffer, offset, count);
            }
        }

        private async Task<int> ReadInternalEncapsulate(byte[] buffer, int offset, int count, CancellationToken token, bool async)
        {
            int readBytes = 0;
            byte[] packetData = ArrayPool<byte>.Shared.Rent(count < TdsEnums.HEADER_LEN ? TdsEnums.HEADER_LEN : count);

            if (_packetBytes == 0)
            {
                // Account for split packets
                while (readBytes < TdsEnums.HEADER_LEN)
                {
                    readBytes += (async ?
                        await ReadInternalAsync(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes, token) :
                        ReadInternalSync(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes)
                   );
                }

                _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 ReadInternalAsync(packetData, 0, count, token) :
                ReadInternalSync(packetData, 0, count)
            );


            _packetBytes -= readBytes;
            
            Buffer.BlockCopy(packetData, 0, buffer, offset, readBytes);

            Array.Clear(packetData, 0, readBytes);
            ArrayPool<byte>.Shared.Return(packetData, clearArray: false);

            return readBytes;
        }

        private async Task<int> ReadInternalAsync(byte[] buffer, int offset, int count, CancellationToken token)
        {
            return await _stream.ReadAsync(buffer, 0, count, token).ConfigureAwait(false);
        }

        private int ReadInternalSync(byte[] buffer, int offset, int count)
        {
            return _stream.Read(buffer, 0, count);
        }

        /// <summary>
        /// The internal write method calls Sync APIs when Async flag is false
        /// </summary>
        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 tunnelled 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;<commit_msg>[release/3.0] SqlClient fix for managed encryption connection failure (#40825)<commit_after>// 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.Buffers;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;

namespace System.Data.SqlClient.SNI
{
    /// <summary>
    /// SSL encapsulated over TDS transport. During SSL handshake, SSL packets are
    /// transported in TDS packet type 0x12. Once SSL handshake has completed, SSL
    /// packets are sent transparently.
    /// </summary>
    internal sealed class SslOverTdsStream : Stream
    {
        private readonly Stream _stream;

        private int _packetBytes = 0;
        private bool _encapsulate;

        private const int PACKET_SIZE_WITHOUT_HEADER = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE - TdsEnums.HEADER_LEN;
        private const int PRELOGIN_PACKET_TYPE = 0x12;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="stream">Underlying stream</param>
        public SslOverTdsStream(Stream stream)
        {
            _stream = stream;
            _encapsulate = true;
        }

        /// <summary>
        /// Finish SSL handshake. Stop encapsulating in TDS.
        /// </summary>
        public void FinishHandshake()
        {
            _encapsulate = false;
        }

        /// <summary>
        /// Read buffer
        /// </summary>
        /// <param name="buffer">Buffer</param>
        /// <param name="offset">Offset</param>
        /// <param name="count">Byte count</param>
        /// <returns>Bytes read</returns>
        public override int Read(byte[] buffer, int offset, int count) =>
            ReadInternal(buffer, offset, count, CancellationToken.None, async: false).GetAwaiter().GetResult();

        /// <summary>
        /// Write Buffer
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public override void Write(byte[] buffer, int offset, int count)
            => WriteInternal(buffer, offset, count, CancellationToken.None, async: false).Wait();

        /// <summary>
        /// Write Buffer Asynchronosly
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
            => WriteInternal(buffer, offset, count, token, async: true);

        /// <summary>
        /// Read Buffer Asynchronosly
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token)
            => ReadInternal(buffer, offset, count, token, async: true);

        /// <summary>
        /// Read Internal is called synchronosly when async is false
        /// </summary>
        private async Task<int> 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<byte>.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)
                    {
                        readBytes += async ?
                            await _stream.ReadAsync(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes, token).ConfigureAwait(false) :
                            _stream.Read(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes);
                    }

                    _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<byte>.Shared.Return(packetData, clearArray: true);
            }
            return readBytes;
        }

        /// <summary>
        /// The internal write method calls Sync APIs when Async flag is false
        /// </summary>
        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 tunnelled 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;
{'fraction_non_alphanumeric': 0.10755362138638483, 'fraction_numerical': 0.003652471246502953, 'mean_word_length': 1.6627353610593834, 'pattern_counts': {'":': 0, '<': 129, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7323359', 'n_tokens_mistral': 3324, 'n_tokens_neox': 3188, 'n_words': 900}