/// <summary> /// Handle receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="header">SMUX header</param> public void HandleReceiveComplete(SNIPacket packet, SNISMUXHeader header) { lock (this) { if (_sendHighwater != header.highwater) { HandleAck(header.highwater); } lock (_receivedPacketQueue) { if (_asyncReceives == 0) { _receivedPacketQueue.Enqueue(packet); _packetEvent.Set(); return; } _asyncReceives--; Debug.Assert(_callbackObject != null); ((TdsParserStateObject)_callbackObject).ReadAsyncCallback(PacketHandle.FromManagedPacket(packet), 0); } } lock (this) { _receiveHighwater++; } SendAckIfNecessary(); }
public SNISMUXHeader Clone() { SNISMUXHeader copy = new SNISMUXHeader(); copy.SMID = SMID; copy.Flags = Flags; copy.SessionId = SessionId; copy.Length = Length; copy.SequenceNumber = SequenceNumber; copy.Highwater = Highwater; return(copy); }
/// <summary> /// Generate a packet with SMUX header /// </summary> /// <param name="packet">SNI packet</param> /// <returns>The packet with the SMUx header set.</returns> private SNIPacket SetPacketSMUXHeader(SNIPacket packet) { Debug.Assert(packet.ReservedHeaderSize == SNISMUXHeader.HEADER_LENGTH, "mars handle attempting to smux packet without smux reservation"); Debug.Assert(Monitor.IsEntered(this), "cannot create mux header outside lock"); SNISMUXHeader header = SetupSMUXHeader(packet.DataLength, SNISMUXFlags.SMUX_DATA); header.Write(packet.GetHeaderBuffer(SNISMUXHeader.HEADER_LENGTH)); packet.SetHeaderActive(); #if DEBUG SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Setting SMUX_DATA header in current header for packet {1}", args0: ConnectionId, args1: packet?._id); #endif return(packet); }
/// <summary> /// Handle receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="header">SMUX header</param> public void HandleReceiveComplete(SNIPacket packet, SNISMUXHeader header) { long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(s_className); try { lock (this) { if (_sendHighwater != header.highwater) { SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, header.highwater {1}, _sendHighwater {2}, Handle Ack with header.highwater", args0: ConnectionId, args1: header?.highwater, args2: _sendHighwater); HandleAck(header.highwater); } lock (_receivedPacketQueue) { if (_asyncReceives == 0) { _receivedPacketQueue.Enqueue(packet); _packetEvent.Set(); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _receivedPacketQueue count {3}, packet event set", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: _receivedPacketQueue?.Count); return; } _asyncReceives--; Debug.Assert(_callbackObject != null); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _asyncReceives {3}", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: _asyncReceives); ((TdsParserStateObject)_callbackObject).ReadAsyncCallback(PacketHandle.FromManagedPacket(packet), 0); } _connection.ReturnPacket(packet); } lock (this) { _receiveHighwater++; } SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, _asyncReceives {1}, _receiveHighwater {2}, _sendHighwater {3}, _receiveHighwaterLastAck {4}", args0: ConnectionId, args1: _asyncReceives, args2: _receiveHighwater, args3: _sendHighwater, args4: _receiveHighwaterLastAck); SendAckIfNecessary(); } finally { SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID); } }
private SNISMUXHeader SetupSMUXHeader(int length, SNISMUXFlags flags) { Debug.Assert(Monitor.IsEntered(this), "must take lock on self before updating smux header"); SNISMUXHeader header = new SNISMUXHeader(); header.Set( smid: 83, flags: (byte)flags, sessionID: _sessionId, length: (uint)SNISMUXHeader.HEADER_LENGTH + (uint)length, sequenceNumber: ((flags == SNISMUXFlags.SMUX_FIN) || (flags == SNISMUXFlags.SMUX_ACK)) ? _sequenceNumber - 1 : _sequenceNumber++, highwater: _receiveHighwater ); _receiveHighwaterLastAck = header.Highwater; return(header); }
/// <summary> /// Handle receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="header">SMUX header</param> public void HandleReceiveComplete(SNIPacket packet, SNISMUXHeader header) { long scopeID = SqlClientEventSource.Log.SNIScopeEnterEvent("<sc.SNI.SNIMarsHandle.HandleReceiveComplete |SNI|INFO|SCOPE>"); try { lock (this) { if (_sendHighwater != header.highwater) { HandleAck(header.highwater); } lock (_receivedPacketQueue) { if (_asyncReceives == 0) { _receivedPacketQueue.Enqueue(packet); _packetEvent.Set(); return; } _asyncReceives--; Debug.Assert(_callbackObject != null); ((TdsParserStateObject)_callbackObject).ReadAsyncCallback(PacketHandle.FromManagedPacket(packet), 0); } _connection.ReturnPacket(packet); } lock (this) { _receiveHighwater++; } SendAckIfNecessary(); } finally { SqlClientEventSource.Log.SNIScopeLeaveEvent(scopeID); } }
/// <summary> /// Handle receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="header">SMUX header</param> public void HandleReceiveComplete(SNIPacket packet, SNISMUXHeader header) { 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 != header.Highwater) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, header.highwater {1}, _sendHighwater {2}, Handle Ack with header.highwater", args0: ConnectionId, args1: header.Highwater, args2: _sendHighwater); HandleAck(header.Highwater); } lock (_receivedPacketQueue) { if (_asyncReceives == 0) { _receivedPacketQueue.Enqueue(packet); _packetEvent.Set(); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _receivedPacketQueue count {3}, packet event set", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: _receivedPacketQueue?.Count); return; } _asyncReceives--; Debug.Assert(_callbackObject != null); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _sequenceNumber {1}, _sendHighwater {2}, _asyncReceives {3}", args0: ConnectionId, args1: _sequenceNumber, args2: _sendHighwater, args3: _asyncReceives); ((TdsParserStateObject)_callbackObject).ReadAsyncCallback(PacketHandle.FromManagedPacket(packet), 0); } _connection.ReturnPacket(packet); } lock (this) { _receiveHighwater++; } SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, _asyncReceives {1}, _receiveHighwater {2}, _sendHighwater {3}, _receiveHighwaterLastAck {4}", args0: ConnectionId, args1: _asyncReceives, args2: _receiveHighwater, args3: _sendHighwater, args4: _receiveHighwaterLastAck); SendAckIfNecessary(); } }
/// <summary> /// Send control packet /// </summary> /// <param name="flags">SMUX header flags</param> private void SendControlPacket(SNISMUXFlags flags) { using (TrySNIEventScope.Create("SNIMarsHandle.SendControlPacket | SNI | INFO | SCOPE | Entering Scope {0}")) { SNIPacket packet = RentPacket(headerSize: SNISMUXHeader.HEADER_LENGTH, dataSize: 0); #if DEBUG SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Packet rented {1}, packet dataLeft {2}", args0: ConnectionId, args1: packet?._id, args2: packet?.DataLeft); #endif lock (this) { SNISMUXHeader header = SetupSMUXHeader(0, flags); header.Write(packet.GetHeaderBuffer(SNISMUXHeader.HEADER_LENGTH)); packet.SetHeaderActive(); } _connection.Send(packet); ReturnPacket(packet); #if DEBUG SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsHandle), EventType.INFO, "MARS Session Id {0}, Packet returned {1}, packet dataLeft {2}", args0: ConnectionId, args1: packet?._id, args2: packet?.DataLeft); ; #endif } }
/// <summary> /// Process a receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="sniErrorCode">SNI error code</param> public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode) { long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent("<sc.SNI.SNIMarsConnection.HandleReceiveComplete |SNI|INFO|SCOPE>"); try { SNISMUXHeader currentHeader = null; SNIPacket currentPacket = null; SNIMarsHandle currentSession = null; if (sniErrorCode != TdsEnums.SNI_SUCCESS) { lock (this) { HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.SNIMarsConnection.HandleReceiveComplete |SNI|ERR> not successful."); return; } } while (true) { lock (this) { if (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { currentHeader = null; currentPacket = null; currentSession = null; while (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { int bytesTaken = packet.TakeData(_headerBytes, _currentHeaderByteCount, SNISMUXHeader.HEADER_LENGTH - _currentHeaderByteCount); _currentHeaderByteCount += bytesTaken; if (bytesTaken == 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { SqlClientEventSource.Log.TrySNITraceEvent("<sc.SNI.SNIMarsConnection.HandleReceiveComplete |SNI|ERR> not successful."); return; } HandleReceiveError(packet); return; } } _currentHeader.Read(_headerBytes); _dataBytesLeft = (int)_currentHeader.length; _currentPacket = _lowerHandle.RentPacket(headerSize: 0, dataSize: (int)_currentHeader.length); } currentHeader = _currentHeader; currentPacket = _currentPacket; if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { if (_dataBytesLeft > 0) { int length = packet.TakeData(_currentPacket, _dataBytesLeft); _dataBytesLeft -= length; if (_dataBytesLeft > 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); return; } } } _currentHeaderByteCount = 0; if (!_sessions.ContainsKey(_currentHeader.sessionId)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, Strings.SNI_ERROR_5); HandleReceiveError(packet); _lowerHandle.Dispose(); _lowerHandle = null; return; } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_FIN) { _sessions.Remove(_currentHeader.sessionId); } else { currentSession = _sessions[_currentHeader.sessionId]; } } if (currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { currentSession.HandleReceiveComplete(currentPacket, currentHeader); } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_ACK) { try { currentSession.HandleAck(currentHeader.highwater); } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); } Debug.Assert(_currentPacket == currentPacket, "current and _current are not the same"); ReturnPacket(currentPacket); currentPacket = null; _currentPacket = null; } lock (this) { if (packet.DataLeft == 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); return; } } } } finally { SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID); } }
/// <summary> /// Process a receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="sniErrorCode">SNI error code</param> public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode) { SNISMUXHeader currentHeader = null; SNIPacket currentPacket = null; SNIMarsHandle currentSession = null; if (sniErrorCode != TdsEnums.SNI_SUCCESS) { lock (this) { HandleReceiveError(packet); return; } } while (true) { lock (this) { if (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { currentHeader = null; currentPacket = null; currentSession = null; while (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { int bytesTaken = packet.TakeData(_headerBytes, _currentHeaderByteCount, SNISMUXHeader.HEADER_LENGTH - _currentHeaderByteCount); _currentHeaderByteCount += bytesTaken; if (bytesTaken == 0) { packet.Dispose(); packet = null; sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); return; } } _currentHeader.Read(_headerBytes); _dataBytesLeft = (int)_currentHeader.length; _currentPacket = new SNIPacket((int)_currentHeader.length); } currentHeader = _currentHeader; currentPacket = _currentPacket; if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { if (_dataBytesLeft > 0) { int length = packet.TakeData(_currentPacket, _dataBytesLeft); _dataBytesLeft -= length; if (_dataBytesLeft > 0) { packet.Dispose(); packet = null; sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); return; } } } _currentHeaderByteCount = 0; if (!_sessions.ContainsKey(_currentHeader.sessionId)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, string.Empty); HandleReceiveError(packet); _lowerHandle.Dispose(); _lowerHandle = null; return; } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_FIN) { _sessions.Remove(_currentHeader.sessionId); } else { currentSession = _sessions[_currentHeader.sessionId]; } } if (currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { currentSession.HandleReceiveComplete(currentPacket, currentHeader); } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_ACK) { try { currentSession.HandleAck(currentHeader.highwater); } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); } } lock (this) { if (packet.DataLeft == 0) { packet.Dispose(); packet = null; sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); return; } } } }
public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode) { using (TrySNIEventScope.Create(nameof(SNIMarsConnection))) { if (sniErrorCode != TdsEnums.SNI_SUCCESS) { lock (DemuxerSync) { HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.ERR, "MARS Session Id {0}, Handled receive error code: {1}", args0: _lowerHandle?.ConnectionId, args1: sniErrorCode); return; } } State state = State.Demux; State nextState = State.Demux; SNISMUXHeader handleHeader = default; SNIMarsHandle handleSession = null; SNIPacket handlePacket = null; while (state != State.Error && state != State.Finish) { switch (state) { case State.Demux: lock (DemuxerSync) { switch (_demuxState) { case DemuxState.Header: int taken = packet.TakeData(_headerBytes, _headerCount, SNISMUXHeader.HEADER_LENGTH - _headerCount); _headerCount += taken; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, took {1} header bytes", args0: _lowerHandle?.ConnectionId, args1: packet.DataLeft, args2: taken); if (_headerCount == SNISMUXHeader.HEADER_LENGTH) { _header.Read(_headerBytes); _payloadLength = (int)_header.Length; _payloadCount = 0; _demuxState = DemuxState.Payload; state = State.Demux; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, header complete, _payloadLength {1}", args0: _lowerHandle?.ConnectionId, args1: _payloadLength); goto case DemuxState.Payload; } else { state = State.Receive; } break; case DemuxState.Payload: if (packet.DataLeft == _payloadLength && _partial == null) { // if the data in the packet being processed is exactly and only the data that is going to sent // on to the parser then don't copy it to a new packet just forward the current packet once we've // fiddled the data pointer so that it skips the header data _partial = packet; packet = null; _partial.SetDataToRemainingContents(); _demuxState = DemuxState.Dispatch; state = State.Demux; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, forwarding packet contents", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); goto case DemuxState.Dispatch; } else { if (_partial == null) { _partial = RentPacket(headerSize: 0, dataSize: _payloadLength); } SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, reconstructing packet contents", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); int wanted = _payloadLength - _payloadCount; int transferred = SNIPacket.TransferData(packet, _partial, wanted); _payloadCount += transferred; SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, took {1} payload bytes", args0: _lowerHandle?.ConnectionId, args1: transferred); if (_payloadCount == _payloadLength) { // payload is complete so dispatch the current packet _demuxState = DemuxState.Dispatch; state = State.Receive; goto case DemuxState.Dispatch; } else if (packet.DataLeft == 0) { // no more data in the delivered packet so wait for a new one _demuxState = DemuxState.Payload; state = State.Receive; } else { // data left in the delivered packet so start the demux loop // again and decode the next packet in the input _headerCount = 0; _demuxState = DemuxState.Header; state = State.Demux; } } break; case DemuxState.Dispatch: if (_sessions.TryGetValue(_header.SessionId, out SNIMarsHandle session)) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, Current Session assigned to Session Id {1}", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); switch ((SNISMUXFlags)_header.Flags) { case SNISMUXFlags.SMUX_DATA: handleSession = session; session = null; handleHeader = _header.Clone(); handlePacket = _partial; _partial = null; // move to the state for sending the data to the mars handle and setup // the state that should be moved to after that operation has succeeded state = State.HandleData; if (packet != null && packet.DataLeft > 0) { nextState = State.Demux; } else { nextState = State.Receive; } break; case SNISMUXFlags.SMUX_ACK: handleSession = session; session = null; handleHeader = _header.Clone(); ReturnPacket(_partial); _partial = null; // move to the state for sending the data to the mars handle and setup // the state that should be moved to after that operation has succeeded state = State.HandleAck; if (packet != null && packet.DataLeft > 0) { nextState = State.Demux; } else { nextState = State.Receive; } break; case SNISMUXFlags.SMUX_FIN: ReturnPacket(_partial); _partial = null; _sessions.Remove(_header.SessionId); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "SMUX_FIN | MARS Session Id {0}, SMUX_FIN flag received, Current Header Session Id {1} removed", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); break; default: Debug.Fail("unknown smux packet flag"); break; } // a full packet has been decoded and queued for sending by setting the state or the // handle it was sent to no longer exists and the handle has been dropped. Now reset the // demuxer state ready to recode another packet _header.Clear(); _headerCount = 0; _demuxState = DemuxState.Header; // if the state is set to demux more data and there is no data left then change // the state to request more data if (state == State.Demux && (packet == null || packet.DataLeft == 0)) { if (packet != null) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, run out of data , queuing receive", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); } state = State.Receive; } } else { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, string.Empty); HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.ERR, "Current Header Session Id {0} not found, MARS Session Id {1} will be destroyed, New SNI error created: {2}", args0: _header.SessionId, args1: _lowerHandle?.ConnectionId, args2: sniErrorCode); packet = null; _lowerHandle.Dispose(); _lowerHandle = null; state = State.Error; } break; } } break; case State.HandleAck: Debug.Assert(handleSession != null, "dispatching ack to null SNIMarsHandle"); Debug.Assert(!Monitor.IsEntered(DemuxerSync), "do not dispatch ack to session handle while holding the demuxer lock"); try { handleSession.HandleAck(handleHeader.Highwater); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "SMUX_ACK | MARS Session Id {0}, Current Session {1} handled ack", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); } finally { handleHeader = default; handleSession = null; } state = nextState; nextState = State.Finish; break; case State.HandleData: Debug.Assert(handleSession != null, "dispatching data to null SNIMarsHandle"); Debug.Assert(handlePacket != null, "dispatching null data to SNIMarsHandle"); Debug.Assert(!Monitor.IsEntered(DemuxerSync), "do not dispatch data to session handle while holding the demuxer lock"); // do not ReturnPacket(handlePacket) the receiver is responsible for returning the packet // once it has been used because it can take sync and async paths from to the receiver and // only the reciever can make the decision on when it is completed and can be returned try { handleSession.HandleReceiveComplete(handlePacket, handleHeader); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "SMUX_DATA | MARS Session Id {0}, Current Session {1} completed receiving Data", args0: _lowerHandle?.ConnectionId, args1: _header.SessionId); } finally { handleHeader = default; handleSession = null; handlePacket = null; } state = nextState; nextState = State.Finish; break; case State.Receive: if (packet != null) { Debug.Assert(packet.DataLeft == 0, "loop exit with data remaining"); ReturnPacket(packet); packet = null; } lock (DemuxerSync) { uint receiveResult = ReceiveAsync(ref packet); if (receiveResult == TdsEnums.SNI_SUCCESS_IO_PENDING) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.INFO, "MARS Session Id {0}, SMUX DATA Header SNI Packet received with code {1}", args0: ConnectionId, args1: receiveResult); packet = null; } else { HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNIMarsConnection), EventType.ERR, "MARS Session Id {0}, Handled receive error code: {1}", args0: _lowerHandle?.ConnectionId, args1: receiveResult); } } state = State.Finish; break; } } } }
/// <summary> /// Process a receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="sniErrorCode">SNI error code</param> public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode) { long scopeID = SqlClientEventSource.Log.TrySNIScopeEnterEvent(s_className); try { SNISMUXHeader currentHeader = null; SNIPacket currentPacket = null; SNIMarsHandle currentSession = null; if (sniErrorCode != TdsEnums.SNI_SUCCESS) { lock (this) { HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "MARS Session Id {0}, Handled receive error code: {1}", args0: _lowerHandle?.ConnectionId, args1: sniErrorCode); return; } } while (true) { lock (this) { if (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { currentHeader = null; currentPacket = null; currentSession = null; while (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { int bytesTaken = packet.TakeData(_headerBytes, _currentHeaderByteCount, SNISMUXHeader.HEADER_LENGTH - _currentHeaderByteCount); _currentHeaderByteCount += bytesTaken; if (bytesTaken == 0) { sniErrorCode = ReceiveAsync(ref packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, Non-SMUX Header SNI Packet received with code {1}", args0: ConnectionId, args1: sniErrorCode); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "MARS Session Id {0}, Handled receive error code: {1}", args0: _lowerHandle?.ConnectionId, args1: sniErrorCode); return; } } _currentHeader.Read(_headerBytes); _dataBytesLeft = (int)_currentHeader.length; _currentPacket = _lowerHandle.RentPacket(headerSize: 0, dataSize: (int)_currentHeader.length); #if DEBUG SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, _dataBytesLeft {1}, _currentPacket {2}, Reading data of length: _currentHeader.length {3}", args0: _lowerHandle?.ConnectionId, args1: _dataBytesLeft, args2: currentPacket?._id, args3: _currentHeader?.length); #endif } currentHeader = _currentHeader; currentPacket = _currentPacket; if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { if (_dataBytesLeft > 0) { int length = packet.TakeData(_currentPacket, _dataBytesLeft); _dataBytesLeft -= length; if (_dataBytesLeft > 0) { sniErrorCode = ReceiveAsync(ref packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, SMUX DATA Header SNI Packet received with code {1}, _dataBytesLeft {2}", args0: ConnectionId, args1: sniErrorCode, args2: _dataBytesLeft); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "MARS Session Id {0}, Handled receive error code: {1}", args0: _lowerHandle?.ConnectionId, args1: sniErrorCode); return; } } } _currentHeaderByteCount = 0; if (!_sessions.ContainsKey(_currentHeader.sessionId)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, Strings.SNI_ERROR_5); HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "Current Header Session Id {0} not found, MARS Session Id {1} will be destroyed, New SNI error created: {2}", args0: _currentHeader?.sessionId, args1: _lowerHandle?.ConnectionId, args2: sniErrorCode); _lowerHandle.Dispose(); _lowerHandle = null; return; } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_FIN) { _sessions.Remove(_currentHeader.sessionId); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "SMUX_FIN | MARS Session Id {0}, SMUX_FIN flag received, Current Header Session Id {1} removed", args0: _lowerHandle?.ConnectionId, args1: _currentHeader?.sessionId); } else { currentSession = _sessions[_currentHeader.sessionId]; SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "MARS Session Id {0}, Current Session assigned to Session Id {1}", args0: _lowerHandle?.ConnectionId, args1: _currentHeader?.sessionId); } } if (currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { currentSession.HandleReceiveComplete(currentPacket, currentHeader); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "SMUX_DATA | MARS Session Id {0}, Current Session {1} completed receiving Data", args0: _lowerHandle?.ConnectionId, args1: _currentHeader?.sessionId); } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_ACK) { try { currentSession.HandleAck(currentHeader.highwater); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "SMUX_ACK | MARS Session Id {0}, Current Session {1} handled ack", args0: _lowerHandle?.ConnectionId, args1: _currentHeader?.sessionId); } catch (Exception e) { SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "SMUX_ACK | MARS Session Id {0}, Exception occurred: {2}", args0: _currentHeader?.sessionId, args1: e?.Message); SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); } #if DEBUG Debug.Assert(_currentPacket == currentPacket, "current and _current are not the same"); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.INFO, "SMUX_ACK | MARS Session Id {0}, Current Packet {1} returned", args0: _lowerHandle?.ConnectionId, args1: currentPacket?._id); #endif ReturnPacket(currentPacket); currentPacket = null; _currentPacket = null; } lock (this) { if (packet.DataLeft == 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(packet); SqlClientEventSource.Log.TrySNITraceEvent(s_className, EventType.ERR, "MARS Session Id {0}, packet.DataLeft 0, SNI error {2}", args0: _lowerHandle?.ConnectionId, args1: sniErrorCode); return; } } } } finally { SqlClientEventSource.Log.TrySNIScopeLeaveEvent(scopeID); } }