Jelajahi Sumber

TargetResponseHelper improvements

Tal Aloni 8 tahun lalu
induk
melakukan
09e74429d5

+ 1 - 0
ISCSI/ISCSI.csproj

@@ -67,6 +67,7 @@
     <Compile Include="SCSI\Enums\SCSIStatusCodeName.cs" />
     <Compile Include="SCSI\Enums\ServiceAction.cs" />
     <Compile Include="SCSI\Enums\VitalProductDataPageName.cs" />
+    <Compile Include="Server\Exceptions\InvalidTargetTransferTagException.cs" />
     <Compile Include="Server\ISCSIServer.cs" />
     <Compile Include="Server\PDUHelper.cs" />
     <Compile Include="SCSITarget\VirtualSCSITarget.cs" />

+ 22 - 0
ISCSI/Server/Exceptions/InvalidTargetTransferTagException.cs

@@ -0,0 +1,22 @@
+/* Copyright (C) 2012-2016 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,
+ * either version 3 of the License, or (at your option) any later version.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ISCSI.Server
+{
+    public class InvalidTargetTransferTagException : Exception
+    {
+        public uint TargetTransferTag;
+
+        public InvalidTargetTransferTagException(uint targetTransferTag) : base("Invalid TargetTransferTag: " + targetTransferTag)
+        {
+            TargetTransferTag = targetTransferTag;
+        }
+    }
+}

+ 25 - 6
ISCSI/Server/ISCSIServer.cs

@@ -440,22 +440,41 @@ namespace ISCSI.Server
                 {
                     // RFC 3720: the iSCSI target layer MUST deliver the commands for execution (to the SCSI execution engine) in the order specified by CmdSN.
                     // e.g. read requests should not be executed while previous write request data is being received (via R2T)
-                    List<SCSICommandPDU> commandsToExecute;
-                    List<ISCSIPDU> responseList;
+                    List<SCSICommandPDU> commandsToExecute = null;
+                    List<ReadyToTransferPDU> readyToTransferPDUs = new List<ReadyToTransferPDU>();
                     if (pdu is SCSIDataOutPDU)
                     {
                         SCSIDataOutPDU request = (SCSIDataOutPDU)pdu;
                         ISCSIServer.Log("[{0}][ProcessPDU] SCSIDataOutPDU: Target transfer tag: {1}, LUN: {2}, Buffer offset: {3}, Data segment length: {4}, DataSN: {5}, Final: {6}", state.ConnectionIdentifier, request.TargetTransferTag, (ushort)request.LUN, request.BufferOffset, request.DataSegmentLength, request.DataSN, request.Final);
-                        responseList = TargetResponseHelper.GetReadyToTransferPDUs(request, state.Target, state.SessionParameters, state.ConnectionParameters, out commandsToExecute);
+                        try
+                        {
+                            readyToTransferPDUs = TargetResponseHelper.GetReadyToTransferPDUs(request, state.Target, state.SessionParameters, state.ConnectionParameters, out commandsToExecute);
+                        }
+                        catch (InvalidTargetTransferTagException ex)
+                        {
+                            ISCSIServer.Log("[{0}] Invalid TargetTransferTag: {1}", state.ConnectionIdentifier, ex.TargetTransferTag);
+                            RejectPDU reject = new RejectPDU();
+                            reject.InitiatorTaskTag = request.InitiatorTaskTag;
+                            reject.Reason = RejectReason.InvalidPDUField;
+                            reject.Data = ByteReader.ReadBytes(request.GetBytes(), 0, 48);
+                            TrySendPDU(state, reject);
+                        }
                     }
                     else
                     {
                         SCSICommandPDU command = (SCSICommandPDU)pdu;
                         ISCSIServer.Log("[{0}][ProcessPDU] SCSICommandPDU: CmdSN: {1}, LUN: {2}, Data segment length: {3}, Expected Data Transfer Length: {4}, Final: {5}", state.ConnectionIdentifier, command.CmdSN, (ushort)command.LUN, command.DataSegmentLength, command.ExpectedDataTransferLength, command.Final);
-                        responseList = TargetResponseHelper.GetReadyToTransferPDUs(command, state.Target, state.SessionParameters, state.ConnectionParameters, out commandsToExecute);
+                        readyToTransferPDUs = TargetResponseHelper.GetReadyToTransferPDUs(command, state.Target, state.SessionParameters, state.ConnectionParameters, out commandsToExecute);
                     }
-
-                    state.RunningSCSICommands.Add(commandsToExecute.Count);
+                    foreach (ReadyToTransferPDU readyToTransferPDU in readyToTransferPDUs)
+                    {
+                        TrySendPDU(state, readyToTransferPDU);
+                    }
+                    if (commandsToExecute != null)
+                    {
+                        state.RunningSCSICommands.Add(commandsToExecute.Count);
+                    }
+                    List<ISCSIPDU> responseList = new List<ISCSIPDU>();
                     foreach(SCSICommandPDU command in commandsToExecute)
                     {
                         List<ISCSIPDU> commandResponseList = TargetResponseHelper.GetSCSICommandResponse(command, state.Target, state.SessionParameters, state.ConnectionParameters);

+ 5 - 11
ISCSI/Server/TargetResponseHelper.cs

@@ -17,10 +17,10 @@ namespace ISCSI.Server
 {
     public class TargetResponseHelper
     {
-        internal static List<ISCSIPDU> GetReadyToTransferPDUs(SCSICommandPDU command, SCSITarget target, SessionParameters session, ConnectionParameters connection, out List<SCSICommandPDU> commandsToExecute)
+        internal static List<ReadyToTransferPDU> GetReadyToTransferPDUs(SCSICommandPDU command, SCSITarget target, SessionParameters session, ConnectionParameters connection, out List<SCSICommandPDU> commandsToExecute)
         {
             // We return either SCSIResponsePDU or List<SCSIDataInPDU>
-            List<ISCSIPDU> responseList = new List<ISCSIPDU>();
+            List<ReadyToTransferPDU> responseList = new List<ReadyToTransferPDU>();
             commandsToExecute = new List<SCSICommandPDU>();
             
             string connectionIdentifier = ConnectionState.GetConnectionIdentifier(session, connection);
@@ -58,22 +58,16 @@ namespace ISCSI.Server
             return responseList;
         }
 
-        internal static List<ISCSIPDU> GetReadyToTransferPDUs(SCSIDataOutPDU request, SCSITarget target, SessionParameters session, ConnectionParameters connection, out List<SCSICommandPDU> commandsToExecute)
+        internal static List<ReadyToTransferPDU> GetReadyToTransferPDUs(SCSIDataOutPDU request, SCSITarget target, SessionParameters session, ConnectionParameters connection, out List<SCSICommandPDU> commandsToExecute)
         {
-            List<ISCSIPDU> responseList = new List<ISCSIPDU>();
+            List<ReadyToTransferPDU> responseList = new List<ReadyToTransferPDU>();
             commandsToExecute = new List<SCSICommandPDU>();
 
             string connectionIdentifier = ConnectionState.GetConnectionIdentifier(session, connection);
             TransferEntry transfer = connection.GetTransferEntry(request.TargetTransferTag);
             if (transfer == null)
             {
-                ISCSIServer.Log("[{0}][GetSCSIDataOutResponsePDU] Invalid TargetTransferTag {1}", connectionIdentifier, request.TargetTransferTag);
-                RejectPDU reject = new RejectPDU();
-                reject.InitiatorTaskTag = request.InitiatorTaskTag;
-                reject.Reason = RejectReason.InvalidPDUField;
-                reject.Data = ByteReader.ReadBytes(request.GetBytes(), 0, 48);
-                responseList.Add(reject);
-                return responseList;
+                throw new InvalidTargetTransferTagException(request.TargetTransferTag);
             }
 
             uint offset = request.BufferOffset;