/// <summary>
/// SMUX packet header
/// </summary>
- internal class SNISMUXHeader
+ internal sealed class SNISMUXHeader
{
public const int HEADER_LENGTH = 16;
public uint length;
public uint sequenceNumber;
public uint highwater;
+
+ public void Read(byte[] bytes)
+ {
+ SMID = bytes[0];
+ flags = bytes[1];
+ sessionId = BitConverter.ToUInt16(bytes, 2);
+ length = BitConverter.ToUInt32(bytes, 4) - SNISMUXHeader.HEADER_LENGTH;
+ sequenceNumber = BitConverter.ToUInt32(bytes, 8);
+ highwater = BitConverter.ToUInt32(bytes, 12);
+ }
+
+ public void Write(Span<byte> bytes)
+ {
+ uint value = highwater;
+ // access the highest element first to cause the largest range check in the jit, then fill in the rest of the value and carry on as normal
+ bytes[15] = (byte)((value >> 24) & 0xff);
+ bytes[12] = (byte)(value & 0xff); // BitConverter.GetBytes(_currentHeader.highwater).CopyTo(headerBytes, 12);
+ bytes[13] = (byte)((value >> 8) & 0xff);
+ bytes[14] = (byte)((value >> 16) & 0xff);
+
+ bytes[0] = SMID; // BitConverter.GetBytes(_currentHeader.SMID).CopyTo(headerBytes, 0);
+ bytes[1] = flags; // BitConverter.GetBytes(_currentHeader.flags).CopyTo(headerBytes, 1);
+
+ value = sessionId;
+ bytes[2] = (byte)(value & 0xff); // BitConverter.GetBytes(_currentHeader.sessionId).CopyTo(headerBytes, 2);
+ bytes[3] = (byte)((value >> 8) & 0xff);
+
+ value = length;
+ bytes[4] = (byte)(value & 0xff); // BitConverter.GetBytes(_currentHeader.length).CopyTo(headerBytes, 4);
+ bytes[5] = (byte)((value >> 8) & 0xff);
+ bytes[6] = (byte)((value >> 16) & 0xff);
+ bytes[7] = (byte)((value >> 24) & 0xff);
+
+ value = sequenceNumber;
+ bytes[8] = (byte)(value & 0xff); // BitConverter.GetBytes(_currentHeader.sequenceNumber).CopyTo(headerBytes, 8);
+ bytes[9] = (byte)((value >> 8) & 0xff);
+ bytes[10] = (byte)((value >> 16) & 0xff);
+ bytes[11] = (byte)((value >> 24) & 0xff);
+
+ }
}
/// <summary>
private readonly Guid _connectionId = Guid.NewGuid();
private readonly Dictionary<int, SNIMarsHandle> _sessions = new Dictionary<int, SNIMarsHandle>();
private readonly byte[] _headerBytes = new byte[SNISMUXHeader.HEADER_LENGTH];
-
+ private readonly SNISMUXHeader _currentHeader = new SNISMUXHeader();
private SNIHandle _lowerHandle;
private ushort _nextSessionId = 0;
private int _currentHeaderByteCount = 0;
private int _dataBytesLeft = 0;
- private SNISMUXHeader _currentHeader;
private SNIPacket _currentPacket;
/// <summary>
{
handle.HandleReceiveError(packet);
}
+ packet?.Dispose();
}
/// <summary>
if (bytesTaken == 0)
{
+ packet.Dispose();
+ packet = null;
sniErrorCode = ReceiveAsync(ref packet);
if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING)
}
}
- _currentHeader = new SNISMUXHeader()
- {
- SMID = _headerBytes[0],
- flags = _headerBytes[1],
- sessionId = BitConverter.ToUInt16(_headerBytes, 2),
- length = BitConverter.ToUInt32(_headerBytes, 4) - SNISMUXHeader.HEADER_LENGTH,
- sequenceNumber = BitConverter.ToUInt32(_headerBytes, 8),
- highwater = BitConverter.ToUInt32(_headerBytes, 12)
- };
-
+ _currentHeader.Read(_headerBytes);
_dataBytesLeft = (int)_currentHeader.length;
_currentPacket = new SNIPacket((int)_currentHeader.length);
}
if (_dataBytesLeft > 0)
{
+ packet.Dispose();
+ packet = null;
sniErrorCode = ReceiveAsync(ref packet);
if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING)
{
if (packet.DataLeft == 0)
{
+ packet.Dispose();
+ packet = null;
sniErrorCode = ReceiveAsync(ref packet);
if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING)
/// <param name="flags">SMUX header flags</param>
private void SendControlPacket(SNISMUXFlags flags)
{
- byte[] headerBytes = null;
-
+ Span<byte> headerBytes = stackalloc byte[SNISMUXHeader.HEADER_LENGTH];
lock (this)
{
- GetSMUXHeaderBytes(0, (byte)flags, ref headerBytes);
+ GetSMUXHeaderBytes(0, flags, headerBytes);
}
- SNIPacket packet = new SNIPacket();
- packet.SetData(headerBytes, SNISMUXHeader.HEADER_LENGTH);
+ SNIPacket packet = new SNIPacket(SNISMUXHeader.HEADER_LENGTH);
+ packet.AppendData(headerBytes);
_connection.Send(packet);
}
- /// <summary>
- /// Generate SMUX header
- /// </summary>
- /// <param name="length">Packet length</param>
- /// <param name="flags">Packet flags</param>
- /// <param name="headerBytes">Header in bytes</param>
- private void GetSMUXHeaderBytes(int length, byte flags, ref byte[] headerBytes)
+ private void GetSMUXHeaderBytes(int length, SNISMUXFlags flags, Span<byte> bytes)
{
- headerBytes = new byte[SNISMUXHeader.HEADER_LENGTH];
-
_currentHeader.SMID = 83;
- _currentHeader.flags = flags;
+ _currentHeader.flags = (byte)flags;
_currentHeader.sessionId = _sessionId;
_currentHeader.length = (uint)SNISMUXHeader.HEADER_LENGTH + (uint)length;
- _currentHeader.sequenceNumber = ((flags == (byte)SNISMUXFlags.SMUX_FIN) || (flags == (byte)SNISMUXFlags.SMUX_ACK)) ? _sequenceNumber - 1 : _sequenceNumber++;
+ _currentHeader.sequenceNumber = ((flags == SNISMUXFlags.SMUX_FIN) || (flags == SNISMUXFlags.SMUX_ACK)) ? _sequenceNumber - 1 : _sequenceNumber++;
_currentHeader.highwater = _receiveHighwater;
_receiveHighwaterLastAck = _currentHeader.highwater;
- BitConverter.GetBytes(_currentHeader.SMID).CopyTo(headerBytes, 0);
- BitConverter.GetBytes(_currentHeader.flags).CopyTo(headerBytes, 1);
- BitConverter.GetBytes(_currentHeader.sessionId).CopyTo(headerBytes, 2);
- BitConverter.GetBytes(_currentHeader.length).CopyTo(headerBytes, 4);
- BitConverter.GetBytes(_currentHeader.sequenceNumber).CopyTo(headerBytes, 8);
- BitConverter.GetBytes(_currentHeader.highwater).CopyTo(headerBytes, 12);
+ _currentHeader.Write(bytes);
}
/// <summary>
private SNIPacket GetSMUXEncapsulatedPacket(SNIPacket packet)
{
uint xSequenceNumber = _sequenceNumber;
- byte[] headerBytes = null;
- GetSMUXHeaderBytes(packet.Length, (byte)SNISMUXFlags.SMUX_DATA, ref headerBytes);
+ Span<byte> header = stackalloc byte[SNISMUXHeader.HEADER_LENGTH];
+ GetSMUXHeaderBytes(packet.Length, SNISMUXFlags.SMUX_DATA, header);
- SNIPacket smuxPacket = new SNIPacket(16 + packet.Length);
- smuxPacket.Description = string.Format("({0}) SMUX packet {1}", packet.Description == null ? "" : packet.Description, xSequenceNumber);
- smuxPacket.AppendData(headerBytes, 16);
- smuxPacket.AppendPacket(packet);
+ SNIPacket smuxPacket = new SNIPacket(SNISMUXHeader.HEADER_LENGTH + packet.Length);
+ smuxPacket.AppendData(header);
+ smuxPacket.AppendPacket(packet);
+ packet.Dispose();
return smuxPacket;
}
_ackEvent.Reset();
}
}
+ SNIPacket encapsulatedPacket = GetSMUXEncapsulatedPacket(packet);
- return _connection.Send(GetSMUXEncapsulatedPacket(packet));
+ return _connection.Send(encapsulatedPacket);
}
/// <summary>
/// <returns>SNI error code</returns>
private uint InternalSendAsync(SNIPacket packet, SNIAsyncCallback callback)
{
- SNIPacket encapsulatedPacket = null;
-
lock (this)
{
if (_sequenceNumber >= _sendHighwater)
return TdsEnums.SNI_QUEUE_FULL;
}
- encapsulatedPacket = GetSMUXEncapsulatedPacket(packet);
+ SNIPacket encapsulatedPacket = GetSMUXEncapsulatedPacket(packet);
if (callback != null)
{
private int _offset;
private string _description;
private SNIAsyncCallback _completionCallback;
- private bool _isBufferFromArrayPool = false;
+ private bool _isBufferFromArrayPool;
public SNIPacket() { }
_length += size;
}
+ public void AppendData(ReadOnlySpan<byte> data)
+ {
+ data.CopyTo(_data.AsSpan(_length));
+ _length += data.Length;
+ }
+
/// <summary>
/// Append another packet
/// </summary>