diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj
index a39afad..0c14c68 100644
--- a/SMBLibrary/SMBLibrary.csproj
+++ b/SMBLibrary/SMBLibrary.csproj
@@ -116,6 +116,7 @@
+
diff --git a/SMBLibrary/Server/SMBConnectionReceiveBuffer.cs b/SMBLibrary/Server/SMBConnectionReceiveBuffer.cs
new file mode 100644
index 0000000..e239589
--- /dev/null
+++ b/SMBLibrary/Server/SMBConnectionReceiveBuffer.cs
@@ -0,0 +1,131 @@
+/* Copyright (C) 2014-2017 Tal Aloni . All rights reserved.
+ *
+ * You can redistribute this program and/or modify it under the terms of
+ * the GNU Lesser Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SMBLibrary.NetBios;
+using Utilities;
+
+namespace SMBLibrary.Server
+{
+ public class SMBConnectionReceiveBuffer
+ {
+ private byte[] m_buffer;
+ private int m_readOffset = 0;
+ private int m_bytesInBuffer = 0;
+ private int? m_packetLength;
+
+ /// Must be large enough to hold the largest possible packet
+ public SMBConnectionReceiveBuffer(int bufferLength)
+ {
+ m_buffer = new byte[bufferLength];
+ }
+
+ public void SetNumberOfBytesReceived(int numberOfBytesReceived)
+ {
+ m_bytesInBuffer += numberOfBytesReceived;
+ }
+
+ public bool HasCompletePacket()
+ {
+ if (m_bytesInBuffer >= 4)
+ {
+ if (!m_packetLength.HasValue)
+ {
+ // The packet is either Direct TCP transport packet (which is an NBT Session Message
+ // Packet) or an NBT packet.
+ byte flags = ByteReader.ReadByte(m_buffer, m_readOffset + 1);
+ int trailerLength = (flags & 0x01) << 16 | BigEndianConverter.ToUInt16(m_buffer, m_readOffset + 2);
+ m_packetLength = 4 + trailerLength;
+ }
+ return m_bytesInBuffer >= m_packetLength.Value;
+ }
+ return false;
+ }
+
+ ///
+ /// HasCompletePacket must be called and return true before calling DequeuePacket
+ ///
+ ///
+ public SessionPacket DequeuePacket()
+ {
+ SessionPacket packet;
+ try
+ {
+ packet = SessionPacket.GetSessionPacket(m_buffer, m_readOffset);
+ }
+ catch (IndexOutOfRangeException ex)
+ {
+ throw new System.IO.InvalidDataException("Invalid Packet", ex);
+ }
+ RemovePacketBytes();
+ return packet;
+ }
+
+ ///
+ /// HasCompletePDU must be called and return true before calling DequeuePDUBytes
+ ///
+ public byte[] DequeuePacketBytes()
+ {
+ byte[] packetBytes = ByteReader.ReadBytes(m_buffer, m_readOffset, m_packetLength.Value);
+ RemovePacketBytes();
+ return packetBytes;
+ }
+
+ private void RemovePacketBytes()
+ {
+ m_bytesInBuffer -= m_packetLength.Value;
+ if (m_bytesInBuffer == 0)
+ {
+ m_readOffset = 0;
+ m_packetLength = null;
+ }
+ else
+ {
+ m_readOffset += m_packetLength.Value;
+ m_packetLength = null;
+ if (!HasCompletePacket())
+ {
+ Array.Copy(m_buffer, m_readOffset, m_buffer, 0, m_bytesInBuffer);
+ m_readOffset = 0;
+ }
+ }
+ }
+
+ public byte[] Buffer
+ {
+ get
+ {
+ return m_buffer;
+ }
+ }
+
+ public int WriteOffset
+ {
+ get
+ {
+ return m_readOffset + m_bytesInBuffer;
+ }
+ }
+
+ public int BytesInBuffer
+ {
+ get
+ {
+ return m_bytesInBuffer;
+ }
+ }
+
+ public int AvailableLength
+ {
+ get
+ {
+ return m_buffer.Length - (m_readOffset + m_bytesInBuffer);
+ }
+ }
+ }
+}
diff --git a/SMBLibrary/Server/SMBServer.cs b/SMBLibrary/Server/SMBServer.cs
index 3e51b10..e3fd875 100644
--- a/SMBLibrary/Server/SMBServer.cs
+++ b/SMBLibrary/Server/SMBServer.cs
@@ -95,13 +95,12 @@ namespace SMBLibrary.Server
}
StateObject state = new StateObject();
- state.ReceiveBuffer = new byte[StateObject.ReceiveBufferSize];
// Disable the Nagle Algorithm for this tcp socket:
clientSocket.NoDelay = true;
state.ClientSocket = clientSocket;
try
{
- clientSocket.BeginReceive(state.ReceiveBuffer, 0, StateObject.ReceiveBufferSize, 0, ReceiveCallback, state);
+ clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
}
catch (ObjectDisposedException)
{
@@ -123,13 +122,10 @@ namespace SMBLibrary.Server
return;
}
- byte[] receiveBuffer = state.ReceiveBuffer;
-
- int bytesReceived;
-
+ int numberOfBytesReceived;
try
{
- bytesReceived = clientSocket.EndReceive(result);
+ numberOfBytesReceived = clientSocket.EndReceive(result);
}
catch (ObjectDisposedException)
{
@@ -140,7 +136,7 @@ namespace SMBLibrary.Server
return;
}
- if (bytesReceived == 0)
+ if (numberOfBytesReceived == 0)
{
// The other side has closed the connection
System.Diagnostics.Debug.Print("[{0}] The other side closed the connection", DateTime.Now.ToString("HH:mm:ss:ffff"));
@@ -148,16 +144,15 @@ namespace SMBLibrary.Server
return;
}
- byte[] currentBuffer = new byte[bytesReceived];
- Array.Copy(receiveBuffer, currentBuffer, bytesReceived);
-
- ProcessCurrentBuffer(currentBuffer, state);
+ SMBConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
+ receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
+ ProcessConnectionBuffer(state);
if (clientSocket.Connected)
{
try
{
- clientSocket.BeginReceive(state.ReceiveBuffer, 0, StateObject.ReceiveBufferSize, 0, ReceiveCallback, state);
+ clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
}
catch (ObjectDisposedException)
{
@@ -168,88 +163,32 @@ namespace SMBLibrary.Server
}
}
- public void ProcessCurrentBuffer(byte[] currentBuffer, StateObject state)
+ public void ProcessConnectionBuffer(StateObject state)
{
Socket clientSocket = state.ClientSocket;
- if (state.ConnectionBuffer.Length == 0)
+ SMBConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
+ while (receiveBuffer.HasCompletePacket())
{
- state.ConnectionBuffer = currentBuffer;
- }
- else
- {
- byte[] oldConnectionBuffer = state.ConnectionBuffer;
- state.ConnectionBuffer = new byte[oldConnectionBuffer.Length + currentBuffer.Length];
- Array.Copy(oldConnectionBuffer, state.ConnectionBuffer, oldConnectionBuffer.Length);
- Array.Copy(currentBuffer, 0, state.ConnectionBuffer, oldConnectionBuffer.Length, currentBuffer.Length);
- }
-
- // we now have all SMB message bytes received so far in state.ConnectionBuffer
- int bytesLeftInBuffer = state.ConnectionBuffer.Length;
-
-
- while (bytesLeftInBuffer >= 4)
- {
- // The packet is either Direct TCP transport packet (which is an NBT Session Message
- // Packet) or an NBT packet.
- int bufferOffset = state.ConnectionBuffer.Length - bytesLeftInBuffer;
- byte flags = ByteReader.ReadByte(state.ConnectionBuffer, bufferOffset + 1);
- int trailerLength = (flags & 0x01) << 16 | BigEndianConverter.ToUInt16(state.ConnectionBuffer, bufferOffset + 2);
- int packetLength = 4 + trailerLength;
-
- if (flags > 0x01)
+ SessionPacket packet = null;
+ try
+ {
+ packet = receiveBuffer.DequeuePacket();
+ }
+ catch (Exception)
{
- System.Diagnostics.Debug.Print("[{0}] Invalid NBT flags", DateTime.Now.ToString("HH:mm:ss:ffff"));
state.ClientSocket.Close();
- return;
}
- if (packetLength > bytesLeftInBuffer)
+ if (packet != null)
{
- break;
+ ProcessPacket(packet, state);
}
- else
- {
- byte[] packetBytes = new byte[packetLength];
- Array.Copy(state.ConnectionBuffer, bufferOffset, packetBytes, 0, packetLength);
- ProcessPacket(packetBytes, state);
- bytesLeftInBuffer -= packetLength;
- if (!clientSocket.Connected)
- {
- // Do not continue to process the buffer if the other side closed the connection
- return;
- }
- }
- }
-
- if (bytesLeftInBuffer > 0)
- {
- byte[] newReceiveBuffer = new byte[bytesLeftInBuffer];
- Array.Copy(state.ConnectionBuffer, state.ConnectionBuffer.Length - bytesLeftInBuffer, newReceiveBuffer, 0, bytesLeftInBuffer);
- state.ConnectionBuffer = newReceiveBuffer;
- }
- else
- {
- state.ConnectionBuffer = new byte[0];
}
}
- public void ProcessPacket(byte[] packetBytes, StateObject state)
+ public void ProcessPacket(SessionPacket packet, StateObject state)
{
- SessionPacket packet = null;
-#if DEBUG
- packet = SessionPacket.GetSessionPacket(packetBytes, 0);
-#else
- try
- {
- packet = SessionPacket.GetSessionPacket(packetBytes, 0);
- }
- catch (Exception)
- {
- state.ClientSocket.Close();
- return;
- }
-#endif
if (packet is SessionRequestPacket && m_transport == SMBTransportType.NetBiosOverTCP)
{
PositiveSessionResponsePacket response = new PositiveSessionResponsePacket();
diff --git a/SMBLibrary/Server/StateObject.cs b/SMBLibrary/Server/StateObject.cs
index 10d189a..0e0c3e6 100644
--- a/SMBLibrary/Server/StateObject.cs
+++ b/SMBLibrary/Server/StateObject.cs
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2016 Tal Aloni . All rights reserved.
+/* Copyright (C) 2014-2017 Tal Aloni . All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
@@ -16,9 +16,8 @@ namespace SMBLibrary.Server
public class StateObject
{
public Socket ClientSocket = null;
- public const int ReceiveBufferSize = 65536;
- public byte[] ReceiveBuffer = new byte[ReceiveBufferSize]; // immediate receive buffer
- public byte[] ConnectionBuffer = new byte[0]; // we append the receive buffer here until we have a complete Message
+ public const int ReceiveBufferSize = 131075; // Largest NBT Session Packet
+ public SMBConnectionReceiveBuffer ReceiveBuffer = new SMBConnectionReceiveBuffer(ReceiveBufferSize);
public int MaxBufferSize;
public bool LargeRead;