/// <summary>
        /// Send a packet synchronously
        /// </summary>
        /// <param name="packet">SNI packet</param>
        /// <returns>SNI error code</returns>
        public override uint Send(SNIPacket packet)
        {
            Debug.Assert(packet.ReservedHeaderSize == SNISMUXHeader.HEADER_LENGTH, "mars handle attempting to send muxed packet without smux reservation in Send");
            using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
            {
                while (true)
                {
                    lock (this)
                    {
                        if (_sequenceNumber < _sendHighwater)
                        {
                            break;
                        }
                    }

                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, Waiting for Acknowledgment event.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
                    _ackEvent.Wait();

                    lock (this)
                    {
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sendPacketQueue count found {1}, Acknowledgment event Reset", args0: ConnectionId, args1: _sendPacketQueue?.Count);
                        _ackEvent.Reset();
                    }
                }

                SNIPacket muxedPacket = null;
                lock (this)
                {
                    muxedPacket = SetPacketSMUXHeader(packet);
                }
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, SMUX Packet is going to be sent.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
                return(_connection.Send(muxedPacket));
            }
        }
Example #2
0
 /// <summary>
 /// Disable SSL
 /// </summary>
 public void DisableSsl()
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         _lowerHandle.DisableSsl();
     }
 }
Example #3
0
 /// <summary>
 /// Test handle for killing underlying connection
 /// </summary>
 public void KillConnection()
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         _lowerHandle.KillConnection();
     }
 }
Example #4
0
 /// <summary>
 /// Enable SSL
 /// </summary>
 public uint EnableSsl(uint options)
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         return(_lowerHandle.EnableSsl(options));
     }
 }
Example #5
0
        /// <summary>
        /// Enable SSL
        /// </summary>
        public override uint EnableSsl(uint options)
        {
            using (TrySNIEventScope.Create(nameof(SNIHandle)))
            {
                _validateCert = (options & TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE) != 0;
                try
                {
                    _sslStream.AuthenticateAsClient(_targetServer, null, SupportedProtocols, false);
                    _sslOverTdsStream.FinishHandshake();
                }
                catch (AuthenticationException aue)
                {
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.ERR, "Connection Id {0}, Authentication exception occurred: {1}", args0: _connectionId, args1: aue?.Message);
                    return(ReportTcpSNIError(aue, SNIError.CertificateValidationErrorCode));
                }
                catch (InvalidOperationException ioe)
                {
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.ERR, "Connection Id {0}, Invalid Operation Exception occurred: {1}", args0: _connectionId, args1: ioe?.Message);
                    return(ReportTcpSNIError(ioe));
                }

                _stream = _sslStream;
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, SSL enabled successfully.", args0: _connectionId);
                return(TdsEnums.SNI_SUCCESS);
            }
        }
Example #6
0
        public override uint ReceiveAsync(ref SNIPacket packet)
        {
            using (TrySNIEventScope.Create(nameof(SNINpHandle)))
            {
                SNIPacket errorPacket;
                packet = RentPacket(headerSize: 0, dataSize: _bufferSize);

                try
                {
                    packet.ReadFromStreamAsync(_stream, _receiveCallback);
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Rented and read packet asynchronously, dataLeft {1}", args0: _connectionId, args1: packet?.DataLeft);
                    return(TdsEnums.SNI_SUCCESS_IO_PENDING);
                }
                catch (ObjectDisposedException ode)
                {
                    errorPacket = packet;
                    packet      = null;
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, ObjectDisposedException occurred: {1}.", args0: _connectionId, args1: ode?.Message);
                    return(ReportErrorAndReleasePacket(errorPacket, ode));
                }
                catch (IOException ioe)
                {
                    errorPacket = packet;
                    packet      = null;
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, IOException occurred: {1}.", args0: _connectionId, args1: ioe?.Message);
                    return(ReportErrorAndReleasePacket(errorPacket, ioe));
                }
            }
        }
Example #7
0
        /// <summary>
        /// Sends request to server, and receives response from server by UDP.
        /// </summary>
        /// <param name="browserHostname">UDP server hostname</param>
        /// <param name="port">UDP server port</param>
        /// <param name="requestPacket">request packet</param>
        /// <returns>response packet from UDP server</returns>
        private static byte[] SendUDPRequest(string browserHostname, int port, byte[] requestPacket)
        {
            using (TrySNIEventScope.Create(nameof(SSRP)))
            {
                Debug.Assert(!string.IsNullOrWhiteSpace(browserHostname), "browserhostname should not be null, empty, or whitespace");
                Debug.Assert(port >= 0 && port <= 65535, "Invalid port");
                Debug.Assert(requestPacket != null && requestPacket.Length > 0, "requestPacket should not be null or 0-length array");

                const int sendTimeOutMs    = 1000;
                const int receiveTimeOutMs = 1000;

                IPAddress address     = null;
                bool      isIpAddress = IPAddress.TryParse(browserHostname, out address);

                byte[] responsePacket = null;
                using (UdpClient client = new UdpClient(!isIpAddress ? AddressFamily.InterNetwork : address.AddressFamily))
                {
                    Task <int> sendTask = client.SendAsync(requestPacket, requestPacket.Length, browserHostname, port);
                    Task <UdpReceiveResult> receiveTask = null;

                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Waiting for UDP Client to fetch Port info.");
                    if (sendTask.Wait(sendTimeOutMs) && (receiveTask = client.ReceiveAsync()).Wait(receiveTimeOutMs))
                    {
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SSRP), EventType.INFO, "Received Port info from UDP Client.");
                        responsePacket = receiveTask.Result.Buffer;
                    }
                }

                return(responsePacket);
            }
        }
Example #8
0
        public SNINpHandle(string serverName, string pipeName, long timerExpire)
        {
            using (TrySNIEventScope.Create(nameof(SNINpHandle)))
            {
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Setting server name = {1}, pipe name = {2}", args0: _connectionId, args1: serverName, args2: pipeName);

                _sendSync     = new object();
                _targetServer = serverName;

                try
                {
                    _pipeStream = new NamedPipeClientStream(
                        serverName,
                        pipeName,
                        PipeDirection.InOut,
                        PipeOptions.Asynchronous | PipeOptions.WriteThrough);

                    bool isInfiniteTimeOut = long.MaxValue == timerExpire;
                    if (isInfiniteTimeOut)
                    {
                        _pipeStream.Connect(Timeout.Infinite);
                    }
                    else
                    {
                        TimeSpan ts = DateTime.FromFileTime(timerExpire) - DateTime.Now;
                        ts = ts.Ticks < 0 ? TimeSpan.FromTicks(0) : ts;

                        _pipeStream.Connect((int)ts.TotalMilliseconds);
                    }
                }
                catch (TimeoutException te)
                {
                    SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.ConnOpenFailedError, te);
                    _status = TdsEnums.SNI_ERROR;
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, Connection Timed out. Error Code 1 Exception = {1}", args0: _connectionId, args1: te?.Message);
                    return;
                }
                catch (IOException ioe)
                {
                    SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.ConnOpenFailedError, ioe);
                    _status = TdsEnums.SNI_ERROR;
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, IO Exception occurred. Error Code 1 Exception = {1}", args0: _connectionId, args1: ioe?.Message);
                    return;
                }

                if (!_pipeStream.IsConnected || !_pipeStream.CanWrite || !_pipeStream.CanRead)
                {
                    SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.ConnOpenFailedError, Strings.SNI_ERROR_40);
                    _status = TdsEnums.SNI_ERROR;
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, Pipe Stream not operational. Error Code 1 Exception = {1}", args0: _connectionId, args1: Strings.SNI_ERROR_1);
                    return;
                }

                _sslOverTdsStream = new SslOverTdsStream(_pipeStream, _connectionId);
                _sslStream        = new SNISslStream(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate));

                _stream = _pipeStream;
                _status = TdsEnums.SNI_SUCCESS;
            }
        }
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            using (TrySNIEventScope.Create(nameof(SslOverTdsStream)))
            {
                if (!_encapsulate)
                {
                    return(await _stream.ReadAsync(buffer, offset, count, cancellationToken));
                }

                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 <byte> .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 <byte> .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 <byte> .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);
                }
            }
        }
Example #10
0
        /// <summary>
        /// We only validate Server name in Certificate to match with "targetServerName".
        /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method]
        /// This method is called as a result of callback for SSL Stream Certificate validation.
        /// </summary>
        /// <param name="targetServerName">Server that client is expecting to connect to</param>
        /// <param name="cert">X.509 certificate</param>
        /// <param name="policyErrors">Policy errors</param>
        /// <returns>True if certificate is valid</returns>
        internal static bool ValidateSslServerCertificate(string targetServerName, X509Certificate cert, SslPolicyErrors policyErrors)
        {
            using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} "))
            {
                if (policyErrors == SslPolicyErrors.None)
                {
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: targetServerName);
                    return(true);
                }

                if ((policyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                {
                    string certServerName = cert.Subject.Substring(cert.Subject.IndexOf('=') + 1);

                    // Verify that target server name matches subject in the certificate
                    if (targetServerName.Length > certServerName.Length)
                    {
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name is of greater length than Subject in Certificate.", args0: targetServerName);
                        return(false);
                    }
                    else if (targetServerName.Length == certServerName.Length)
                    {
                        // Both strings have the same length, so targetServerName must be a FQDN
                        if (!targetServerName.Equals(certServerName, StringComparison.OrdinalIgnoreCase))
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
                            return(false);
                        }
                    }
                    else
                    {
                        if (string.Compare(targetServerName, 0, certServerName, 0, targetServerName.Length, StringComparison.OrdinalIgnoreCase) != 0)
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
                            return(false);
                        }

                        // Server name matches cert name for its whole length, so ensure that the
                        // character following the server name is a '.'. This will avoid
                        // having server name "ab" match "abc.corp.company.com"
                        // (Names have different lengths, so the target server can't be a FQDN.)
                        if (certServerName[targetServerName.Length] != '.')
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName);
                            return(false);
                        }
                    }
                }
                else
                {
                    // Fail all other SslPolicy cases besides RemoteCertificateNameMismatch
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy invalidated certificate.", args0: targetServerName, args1: policyErrors);
                    return(false);
                }
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, Client certificate validated successfully.", args0: targetServerName);
                return(true);
            }
        }
        /// <summary>
        /// Receive a packet synchronously
        /// </summary>
        /// <param name="packet">SNI packet</param>
        /// <param name="timeoutInMilliseconds">Timeout in Milliseconds</param>
        /// <returns>SNI error code</returns>
        public override uint Receive(out SNIPacket packet, int timeoutInMilliseconds)
        {
            using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
            {
                packet = null;
                int  queueCount;
                uint result = TdsEnums.SNI_SUCCESS_IO_PENDING;

                while (true)
                {
                    lock (_receivedPacketQueue)
                    {
                        if (_connectionError != null)
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.ERR, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _connectionError found: {3}.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: _connectionError);
                            return(SNICommon.ReportSNIError(_connectionError));
                        }

                        queueCount = _receivedPacketQueue.Count;
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, W_receivedPacketQueue count {3}.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: queueCount);

                        if (queueCount > 0)
                        {
                            packet = _receivedPacketQueue.Dequeue();

                            if (queueCount == 1)
                            {
                                _packetEvent.Reset();
                                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, packet event reset, _receivedPacketQueue count 1.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
                            }

                            result = TdsEnums.SNI_SUCCESS;
                        }
                    }

                    if (result == TdsEnums.SNI_SUCCESS)
                    {
                        lock (this)
                        {
                            _receiveHighwater++;
                        }

                        SendAckIfNecessary();
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, returning with result {3}.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: result);
                        return(result);
                    }

                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, Waiting for packet event.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
                    if (!_packetEvent.Wait(timeoutInMilliseconds))
                    {
                        SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnTimeoutError, Strings.SNI_ERROR_11);
                        SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _packetEvent wait timed out.", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater);
                        return(TdsEnums.SNI_WAIT_TIMEOUT);
                    }
                }
            }
        }
Example #12
0
 public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
 {
     using (TrySNIEventScope.Create(nameof(SNINpHandle)))
     {
         SNIAsyncCallback cb = callback ?? _sendCallback;
         SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Packet writing to stream, dataLeft {1}", args0: _connectionId, args1: packet?.DataLeft);
         packet.WriteToStreamAsync(_stream, cb, SNIProviders.NP_PROV);
         return(TdsEnums.SNI_SUCCESS_IO_PENDING);
     }
 }
Example #13
0
 /// <summary>
 /// Send a packet asynchronously
 /// </summary>
 /// <param name="packet">SNI packet</param>
 /// <param name="callback">Completion callback</param>
 /// <returns>SNI error code</returns>
 public uint SendAsync(SNIPacket packet, SNIAsyncCallback callback)
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         lock (DemuxerSync)
         {
             return(_lowerHandle.SendAsync(packet, callback));
         }
     }
 }
Example #14
0
 /// <summary>
 /// Check SNI handle connection
 /// </summary>
 /// <returns>SNI error status</returns>
 public uint CheckConnection()
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         lock (DemuxerSync)
         {
             return(_lowerHandle.CheckConnection());
         }
     }
 }
Example #15
0
 /// <summary>
 /// Send a packet asynchronously
 /// </summary>
 /// <param name="packet">SNI packet</param>
 /// <param name="callback">Completion callback</param>
 /// <returns>SNI error code</returns>
 public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
 {
     using (TrySNIEventScope.Create(nameof(SNITCPHandle)))
     {
         SNIAsyncCallback cb = callback ?? _sendCallback;
         packet.WriteToStreamAsync(_stream, cb, SNIProviders.TCP_PROV);
         SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Data sent to stream asynchronously", args0: _connectionId);
         return(TdsEnums.SNI_SUCCESS_IO_PENDING);
     }
 }
Example #16
0
 /// <summary>
 /// Send a packet synchronously
 /// </summary>
 /// <param name="packet">SNI packet</param>
 /// <returns>SNI error code</returns>
 public uint Send(SNIPacket packet)
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
     {
         lock (DemuxerSync)
         {
             return(_lowerHandle.Send(packet));
         }
     }
 }
Example #17
0
        public override uint Send(SNIPacket packet)
        {
            using (TrySNIEventScope.Create(nameof(SNINpHandle)))
            {
                bool releaseLock = false;
                try
                {
                    // is the packet is marked out out-of-band (attention packets only) it must be
                    // sent immediately even if a send of receive operation is already in progress
                    // because out of band packets are used to cancel ongoing operations
                    // so try to take the lock if possible but continue even if it can't be taken
                    if (packet.IsOutOfBand)
                    {
                        Monitor.TryEnter(this, ref releaseLock);
                    }
                    else
                    {
                        Monitor.Enter(this);
                        releaseLock = true;
                    }

                    // this lock ensures that two packets are not being written to the transport at the same time
                    // so that sending a standard and an out-of-band packet are both written atomically no data is
                    // interleaved
                    lock (_sendSync)
                    {
                        try
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Packet writing to stream, dataLeft {1}", args0: _connectionId, args1: packet?.DataLeft);
                            packet.WriteToStream(_stream);
                            return(TdsEnums.SNI_SUCCESS);
                        }
                        catch (ObjectDisposedException ode)
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, ObjectDisposedException occurred: {1}.", args0: _connectionId, args1: ode?.Message);
                            return(ReportErrorAndReleasePacket(packet, ode));
                        }
                        catch (IOException ioe)
                        {
                            SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, IOException occurred: {1}.", args0: _connectionId, args1: ioe?.Message);
                            return(ReportErrorAndReleasePacket(packet, ioe));
                        }
                    }
                }
                finally
                {
                    if (releaseLock)
                    {
                        Monitor.Exit(this);
                    }
                }
            }
        }
        public override void Write(ReadOnlySpan <byte> buffer)
        {
            using (TrySNIEventScope.Create(nameof(SslOverTdsStream)))
            {
                // 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;
                }

                ReadOnlySpan <byte> 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 <byte> .Shared.Rent(packetLength);
                        }
                        else if (packetBuffer.Length < packetLength)
                        {
                            ArrayPool <byte> .Shared.Return(packetBuffer, clearArray : true);

                            packetBuffer = ArrayPool <byte> .Shared.Rent(packetLength);
                        }

                        SetupPreLoginPacketHeader(packetBuffer, dataLength, remaining.Length - dataLength);

                        Span <byte> 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 <byte> .Shared.Return(packetBuffer, clearArray : true);
                    }
                }
            }
        }
        public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            using (TrySNIEventScope.Create(nameof(SslOverTdsStream)))
            {
                if (!_encapsulate)
                {
                    await _stream.WriteAsync(buffer, offset, count).ConfigureAwait(false);

                    Task flushTask = _stream.FlushAsync();
                    if (flushTask.Status == TaskStatus.RanToCompletion)
                    {
                        await flushTask.ConfigureAwait(false);
                    }
                    return;
                }

                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 <byte> .Shared.Rent(packetLength);
                    }
                    else if (packetBuffer.Length < packetLength)
                    {
                        ArrayPool <byte> .Shared.Return(packetBuffer, clearArray : true);

                        packetBuffer = ArrayPool <byte> .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 <byte> .Shared.Return(packetBuffer, clearArray : true);
                }
            }
        }
Example #20
0
        /// <summary>
        /// Validate server certificate
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="cert">X.509 certificate</param>
        /// <param name="chain">X.509 chain</param>
        /// <param name="policyErrors">Policy errors</param>
        /// <returns>true if valid</returns>
        private bool ValidateServerCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
        {
            using (TrySNIEventScope.Create(nameof(SNINpHandle)))
            {
                if (!_validateCert)
                {
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId);
                    return(true);
                }

                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId);
                return(SNICommon.ValidateSslServerCertificate(_targetServer, cert, policyErrors));
            }
        }
        public override int Read(Span <byte> buffer)
        {
            using (TrySNIEventScope.Create(nameof(SslOverTdsStream)))
            {
                if (!_encapsulate)
                {
                    return(_stream.Read(buffer));
                }
                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 <byte> 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);
                }
            }
        }
Example #22
0
        /// <summary>
        /// Start receiving
        /// </summary>
        /// <returns></returns>
        public uint StartReceive()
        {
            using (TrySNIEventScope.Create(nameof(SNIMarsConnection)))
            {
                SNIPacket packet = null;

                if (ReceiveAsync(ref packet) == TdsEnums.SNI_SUCCESS_IO_PENDING)
                {
                    SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, Success IO pending.", args0: ConnectionId);
                    return(TdsEnums.SNI_SUCCESS_IO_PENDING);
                }
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.ERR, "MARS Session Id {0}, Connection not usable.", args0: ConnectionId);
                return(SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnNotUsableError, Strings.SNI_ERROR_19));
            }
        }
        /// <summary>
        /// Send a packet asynchronously
        /// </summary>
        /// <param name="packet">SNI packet</param>
        /// <param name="callback">Completion callback</param>
        /// <returns>SNI error code</returns>
        public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
        {
            using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
            {
                lock (this)
                {
                    _sendPacketQueue.Enqueue(new SNIMarsQueuedPacket(packet, callback ?? _handleSendCompleteCallback));
                }

                SendPendingPackets();
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sendPacketQueue enqueued, count {1}", args0: ConnectionId, args1: _sendPacketQueue?.Count);

                return(TdsEnums.SNI_SUCCESS_IO_PENDING);
            }
        }
 /// <summary>
 /// Handle SMUX acknowledgment
 /// </summary>
 /// <param name="highwater">Send highwater mark</param>
 public void HandleAck(uint highwater)
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
     {
         lock (this)
         {
             if (_sendHighwater != highwater)
             {
                 SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Setting _sendHighwater {1} to highwater {2} and send pending packets.", args0: ConnectionId, args1: _sendHighwater, args2: highwater);
                 _sendHighwater = highwater;
                 SendPendingPackets();
             }
         }
     }
 }
        public override void Write(byte[] buffer, int offset, int count)
        {
            using (TrySNIEventScope.Create(nameof(SslOverTdsStream)))
            {
                // 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;
                }

                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 <byte> .Shared.Rent(packetLength);
                    }
                    else if (packetBuffer.Length < packetLength)
                    {
                        ArrayPool <byte> .Shared.Return(packetBuffer, clearArray : true);

                        packetBuffer = ArrayPool <byte> .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 <byte> .Shared.Return(packetBuffer, clearArray : true);
                }
            }
        }
Example #26
0
        /// <summary>
        /// Creates instance port lookup request (CLNT_UCAST_INST) for given instance name.
        /// </summary>
        /// <param name="instanceName">instance name to lookup port</param>
        /// <returns>Byte array of instance port lookup request (CLNT_UCAST_INST)</returns>
        private static byte[] CreateInstanceInfoRequest(string instanceName)
        {
            Debug.Assert(!string.IsNullOrWhiteSpace(instanceName), "instanceName should not be null, empty, or whitespace");
            using (TrySNIEventScope.Create(nameof(SSRP)))
            {
                const byte ClntUcastInst = 0x04;
                instanceName += char.MinValue;
                int byteCount = Encoding.ASCII.GetByteCount(instanceName);

                byte[] requestPacket = new byte[byteCount + 1];
                requestPacket[0] = ClntUcastInst;
                Encoding.ASCII.GetBytes(instanceName, 0, instanceName.Length, requestPacket, 1);

                return(requestPacket);
            }
        }
 /// <summary>
 /// Dispose object
 /// </summary>
 public override void Dispose()
 {
     using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
     {
         try
         {
             SendControlPacket(SNISMUXFlags.SMUX_FIN);
             SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Sent SMUX_FIN packet to terminate session.", args0: ConnectionId);
         }
         catch (Exception e)
         {
             SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.ERR, "MARS Session Id {0}, Internal exception error = {1}, Member Name={2}", args0: ConnectionId, args1: e?.Message, args2: e?.GetType()?.Name);
             SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e);
         }
     }
 }
Example #28
0
 public override uint CheckConnection()
 {
     using (TrySNIEventScope.Create(nameof(SNINpHandle)))
     {
         if (!_stream.CanWrite || !_stream.CanRead)
         {
             SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.ERR, "Connection Id {0}, Cannot write or read to/from the stream", args0: _connectionId);
             return(TdsEnums.SNI_ERROR);
         }
         else
         {
             SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Can read and write to/from stream.", args0: _connectionId);
             return(TdsEnums.SNI_SUCCESS);
         }
     }
 }
        /// <summary>
        /// Handle send completion
        /// </summary>
        /// <param name="packet">SNI packet</param>
        /// <param name="sniErrorCode">SNI error code</param>
        public void HandleSendComplete(SNIPacket packet, uint sniErrorCode)
        {
            using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
            {
                lock (this)
                {
                    Debug.Assert(_callbackObject != null);

                    ((TdsParserStateObject)_callbackObject).WriteAsyncCallback(PacketHandle.FromManagedPacket(packet), sniErrorCode);
                }
                _connection.ReturnPacket(packet);
#if DEBUG
                SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Returned Packet: {1}", args0: ConnectionId, args1: packet?._id);
#endif
            }
        }
Example #30
0
 /// <summary>
 /// Handle SMUX acknowledgment
 /// </summary>
 /// <param name="highwater">Send highwater mark</param>
 public void HandleAck(uint highwater)
 {
     Debug.Assert(_connection != null && Monitor.IsEntered(_connection.DemuxerSync), "SNIMarsHandle.HandleRecieveComplete should be called while holding the SNIMarsConnection.DemuxerSync because it can cause deadlocks");
     using (TrySNIEventScope.Create(nameof(SNIMarsHandle)))
     {
         lock (this)
         {
             if (_sendHighwater != highwater)
             {
                 SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Setting _sendHighwater {1} to highwater {2} and send pending packets.", args0: ConnectionId, args1: _sendHighwater, args2: highwater);
                 _sendHighwater = highwater;
                 SendPendingPackets();
             }
         }
     }
 }