/// <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)); } }
/// <summary> /// Disable SSL /// </summary> public void DisableSsl() { using (TrySNIEventScope.Create(nameof(SNIMarsConnection))) { _lowerHandle.DisableSsl(); } }
/// <summary> /// Test handle for killing underlying connection /// </summary> public void KillConnection() { using (TrySNIEventScope.Create(nameof(SNIMarsConnection))) { _lowerHandle.KillConnection(); } }
/// <summary> /// Enable SSL /// </summary> public uint EnableSsl(uint options) { using (TrySNIEventScope.Create(nameof(SNIMarsConnection))) { return(_lowerHandle.EnableSsl(options)); } }
/// <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); } }
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)); } } }
/// <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); } }
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); } } }
/// <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); } } } }
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); } }
/// <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)); } } }
/// <summary> /// Check SNI handle connection /// </summary> /// <returns>SNI error status</returns> public uint CheckConnection() { using (TrySNIEventScope.Create(nameof(SNIMarsConnection))) { lock (DemuxerSync) { return(_lowerHandle.CheckConnection()); } } }
/// <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); } }
/// <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)); } } }
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); } } }
/// <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); } } }
/// <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); } } }
/// <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); } } }
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 } }
/// <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(); } } } }