Przeglądaj źródła

Client: Enabled SMB 2.1 Large MTU support

Tal Aloni 5 lat temu
rodzic
commit
b4652935c6

+ 41 - 5
SMBLibrary/Client/SMB2Client.cs

@@ -24,9 +24,10 @@ namespace SMBLibrary.Client
         public const int NetBiosOverTCPPort = 139;
         public const int DirectTCPPort = 445;
 
-        public const uint ClientMaxTransactSize = 65536;
-        public const uint ClientMaxReadSize = 65536;
-        public const uint ClientMaxWriteSize = 65536;
+        public static readonly uint ClientMaxTransactSize = 8388608;
+        public static readonly uint ClientMaxReadSize = 8388608;
+        public static readonly uint ClientMaxWriteSize = 8388608;
+        private static readonly ushort DesiredCredits = 128; 
 
         private SMBTransportType m_transport;
         private bool m_isConnected;
@@ -49,6 +50,7 @@ namespace SMBLibrary.Client
         private ulong m_sessionID;
         private byte[] m_securityBlob;
         private byte[] m_sessionKey;
+        private ushort m_availableCredits = 1;
 
         public SMB2Client()
         {
@@ -388,6 +390,8 @@ namespace SMBLibrary.Client
                     return;
                 }
 
+                m_availableCredits += command.Header.Credits;
+
                 // [MS-SMB2] 3.2.5.1.2 - If the MessageId is 0xFFFFFFFFFFFFFFFF, this is not a reply to a previous request,
                 // and the client MUST NOT attempt to locate the request, but instead process it as follows:
                 // If the command field in the SMB2 header is SMB2 OPLOCK_BREAK, it MUST be processed as specified in 3.2.5.19.
@@ -469,7 +473,32 @@ namespace SMBLibrary.Client
 
         internal void TrySendCommand(SMB2Command request)
         {
-            request.Header.Credits = 1;
+            if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP)
+            {
+                request.Header.CreditCharge = 0;
+                request.Header.Credits = 1;
+                m_availableCredits -= 1;
+            }
+            else
+            {
+                if (request.Header.CreditCharge == 0)
+                {
+                    request.Header.CreditCharge = 1;
+                }
+
+                if (m_availableCredits < request.Header.CreditCharge)
+                {
+                    throw new Exception("Not enough credits");
+                }
+
+                m_availableCredits -= request.Header.CreditCharge;
+
+                if (m_availableCredits < DesiredCredits)
+                {
+                    request.Header.Credits += (ushort)(DesiredCredits - m_availableCredits);
+                }
+            }
+
             request.Header.MessageID = m_messageID;
             request.Header.SessionID = m_sessionID;
             if (m_signingRequired)
@@ -485,7 +514,14 @@ namespace SMBLibrary.Client
                 }
             }
             TrySendCommand(m_clientSocket, request);
-            m_messageID++;
+            if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP)
+            {
+                m_messageID++;
+            }
+            else
+            {
+                m_messageID += request.Header.CreditCharge;
+            }
         }
 
         public uint MaxTransactSize

+ 7 - 1
SMBLibrary/Client/SMB2FileStore.cs

@@ -1,4 +1,4 @@
-/* Copyright (C) 2017-2019 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
+/* Copyright (C) 2017-2020 Tal Aloni <tal.aloni.il@gmail.com>. 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,
@@ -13,6 +13,8 @@ namespace SMBLibrary.Client
 {
     public class SMB2FileStore : ISMBFileStore
     {
+        private const int BytesPerCredit = 65536;
+
         private SMB2Client m_client;
         private uint m_treeID;
 
@@ -69,6 +71,7 @@ namespace SMBLibrary.Client
         {
             data = null;
             ReadRequest request = new ReadRequest();
+            request.Header.CreditCharge = (ushort)Math.Ceiling((double)maxCount / BytesPerCredit);
             request.FileId = (FileID)handle;
             request.Offset = (ulong)offset;
             request.ReadLength = (uint)maxCount;
@@ -91,6 +94,7 @@ namespace SMBLibrary.Client
         {
             numberOfBytesWritten = 0;
             WriteRequest request = new WriteRequest();
+            request.Header.CreditCharge = (ushort)Math.Ceiling((double)data.Length / BytesPerCredit);
             request.FileId = (FileID)handle;
             request.Offset = (ulong)offset;
             request.Data = data;
@@ -128,6 +132,7 @@ namespace SMBLibrary.Client
         {
             result = new List<QueryDirectoryFileInformation>();
             QueryDirectoryRequest request = new QueryDirectoryRequest();
+            request.Header.CreditCharge = (ushort)Math.Ceiling((double)m_client.MaxTransactSize / BytesPerCredit);
             request.FileInformationClass = informationClass;
             request.Reopen = true;
             request.FileId = (FileID)handle;
@@ -279,6 +284,7 @@ namespace SMBLibrary.Client
         {
             output = null;
             IOCtlRequest request = new IOCtlRequest();
+            request.Header.CreditCharge = (ushort)Math.Ceiling((double)maxOutputLength / BytesPerCredit);
             request.CtlCode = ctlCode;
             request.IsFSCtl = true;
             request.FileId = (FileID)handle;