Browse Source

API: Added ISCSITarget.OnTextRequest event to handle vendor specific text requests

Tal Aloni 8 years ago
parent
commit
bea9f05793

+ 8 - 0
ISCSI/ISCSI.PDU/TextRequestPDU.cs

@@ -57,5 +57,13 @@ namespace ISCSI
 
             return base.GetBytes();
         }
+
+        public KeyValuePairList<string, string> TextParameters
+        {
+            set
+            {
+                Text = KeyValuePairUtils.ToNullDelimitedString(value);
+            }
+        }
     }
 }

+ 8 - 0
ISCSI/ISCSI.PDU/TextResponsePDU.cs

@@ -60,5 +60,13 @@ namespace ISCSI
 
             return base.GetBytes();
         }
+
+        public KeyValuePairList<string, string> TextParameters
+        {
+            set
+            {
+                Text = KeyValuePairUtils.ToNullDelimitedString(value);
+            }
+        }
     }
 }

+ 1 - 5
ISCSI/ISCSI.Server/ISCSIServer.PDUProcessor.cs

@@ -97,11 +97,7 @@ namespace ISCSI.Server
                 if (pdu is TextRequestPDU)
                 {
                     TextRequestPDU request = (TextRequestPDU)pdu;
-                    TextResponsePDU response;
-                    lock (m_targets.Lock)
-                    {
-                        response = ServerResponseHelper.GetTextResponsePDU(request, m_targets.GetList());
-                    }
+                    TextResponsePDU response = GetTextResponsePDU(request, state.ConnectionParameters);
                     state.SendQueue.Enqueue(response);
                 }
                 else if (pdu is LogoutRequestPDU)

+ 75 - 0
ISCSI/ISCSI.Server/ISCSIServer.TextRequest.cs

@@ -0,0 +1,75 @@
+/* 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;
+using Utilities;
+
+namespace ISCSI.Server
+{
+    public partial class ISCSIServer
+    {
+        private TextResponsePDU GetTextResponsePDU(TextRequestPDU request, ConnectionParameters connection)
+        {
+            TextResponsePDU response = new TextResponsePDU();
+            response.Final = request.Final;
+            response.InitiatorTaskTag = request.InitiatorTaskTag;
+            if (request.Continue)
+            {
+                connection.AddTextToSequence(request.InitiatorTaskTag, request.Text);
+            }
+            else
+            {
+                string text = connection.AddTextToSequence(request.InitiatorTaskTag, request.Text);
+                connection.RemoveTextSequence(request.InitiatorTaskTag);
+                KeyValuePairList<string, string> requestParameters = KeyValuePairUtils.GetKeyValuePairList(text);
+                // text keys are case sensitive
+                if (requestParameters.ContainsKey("SendTargets"))
+                {
+                    KeyValuePairList<string, string> responseParameters = new KeyValuePairList<string, string>();
+                    lock (m_targets.Lock)
+                    {
+                        foreach (ISCSITarget target in m_targets.GetList())
+                        {
+                            responseParameters.Add("TargetName", target.TargetName);
+                        }
+                    }
+                    response.TextParameters = responseParameters;
+                }
+                else if (connection.Session.IsDiscovery || !IsVendorSpecificRequest(requestParameters))
+                {
+                    KeyValuePairList<string, string> responseParameters = new KeyValuePairList<string, string>();
+                    foreach (KeyValuePair<string, string> entry in requestParameters)
+                    {
+                        responseParameters.Add(entry.Key, "Reject");
+                    }
+                    response.TextParameters = responseParameters;
+                }
+                else
+                {
+                    // RFC 3720: Vendor specific keys MUST ONLY be used in normal sessions
+                    // Vendor specific text request, let the target handle it:
+                    response.TextParameters = connection.Session.Target.GetTextResponse(requestParameters);
+                }
+            }
+            return response;
+        }
+        
+        private static bool IsVendorSpecificRequest(KeyValuePairList<string, string> requestParameters)
+        {
+            foreach(string key in requestParameters.Keys)
+            {
+                // RFC 3720: Implementers may introduce new keys by prefixing them with "X-" [..] or X# if registered with IANA.
+                if (!(key.StartsWith("X-") || key.StartsWith("X#")))
+                {
+                    return false;   
+                }
+            }
+            return (requestParameters.Count > 0);
+        }
+    }
+}

+ 12 - 0
ISCSI/ISCSI.Server/ISCSITarget.cs

@@ -18,6 +18,7 @@ namespace ISCSI.Server
         private string m_targetName; // ISCSI name
         private SCSITarget m_target;
         public event EventHandler<AuthorizationRequestArgs> OnAuthorizationRequest;
+        public event EventHandler<TextRequestArgs> OnTextRequest;
         public event EventHandler<SessionTerminationArgs> OnSessionTermination;
 
         public ISCSITarget(string targetName, List<Disk> disks) : this(targetName, new VirtualSCSITarget(disks))
@@ -63,6 +64,17 @@ namespace ISCSI.Server
             return true;
         }
 
+        internal KeyValuePairList<string, string> GetTextResponse(KeyValuePairList<string, string> requestParameters)
+        {
+            EventHandler<TextRequestArgs> handler = OnTextRequest;
+            if (handler != null)
+            {
+                TextRequestArgs args = new TextRequestArgs(requestParameters);
+                return args.ResponseParaemeters;
+            }
+            return new KeyValuePairList<string, string>();
+        }
+
         internal void NotifySessionTermination(string initiatorName, ulong isid, SessionTerminationReason reason)
         {
             EventHandler<SessionTerminationArgs> handler = OnSessionTermination;

+ 0 - 14
ISCSI/ISCSI.Server/ServerResponseHelper.cs

@@ -37,20 +37,6 @@ namespace ISCSI.Server
             return response;
         }
 
-        internal static TextResponsePDU GetTextResponsePDU(TextRequestPDU request, List<ISCSITarget> targets)
-        {
-            TextResponsePDU response = new TextResponsePDU();
-            response.Final = true;
-            response.InitiatorTaskTag = request.InitiatorTaskTag;
-            KeyValuePairList<string, string> entries = new KeyValuePairList<string, string>();
-            foreach (ISCSITarget target in targets)
-            {
-                entries.Add("TargetName", target.TargetName);
-            }
-            response.Text = KeyValuePairUtils.ToNullDelimitedString(entries);
-            return response;
-        }
-
         internal static LogoutResponsePDU GetLogoutResponsePDU(LogoutRequestPDU request, LogoutResponse responseCode)
         {
             LogoutResponsePDU response = new LogoutResponsePDU();

+ 21 - 0
ISCSI/ISCSI.Server/TargetEventArgs/TextRequestArgs.cs

@@ -0,0 +1,21 @@
+/* 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 Utilities;
+
+namespace ISCSI.Server
+{
+    public class TextRequestArgs : EventArgs
+    {
+        public KeyValuePairList<string, string> RequestParaemeters;
+        public KeyValuePairList<string, string> ResponseParaemeters = new KeyValuePairList<string, string>();
+
+        public TextRequestArgs(KeyValuePairList<string, string> requestParaemeters)
+        {
+        }
+    }
+}

+ 2 - 0
ISCSI/ISCSI.csproj

@@ -72,6 +72,7 @@
     <Compile Include="ISCSI.Server\ISCSIServer.Login.cs" />
     <Compile Include="ISCSI.Server\ISCSIServer.Parameters.cs" />
     <Compile Include="ISCSI.Server\ISCSIServer.PDUProcessor.cs" />
+    <Compile Include="ISCSI.Server\ISCSIServer.TextRequest.cs" />
     <Compile Include="ISCSI.Server\ISCSISession.cs" />
     <Compile Include="ISCSI.Server\ISCSITarget.cs" />
     <Compile Include="ISCSI.Server\PDUHelper.cs" />
@@ -79,6 +80,7 @@
     <Compile Include="ISCSI.Server\SessionManager.cs" />
     <Compile Include="ISCSI.Server\TargetEventArgs\AuthorizationRequestArgs.cs" />
     <Compile Include="ISCSI.Server\TargetEventArgs\SessionTerminationArgs.cs" />
+    <Compile Include="ISCSI.Server\TargetEventArgs\TextRequestArgs.cs" />
     <Compile Include="ISCSI.Server\TargetList.cs" />
     <Compile Include="ISCSI.Server\TargetResponseHelper.cs" />
     <Compile Include="SCSI\Enums\AddressingMethod.cs" />