Jelajahi Sumber

Ability to add iSCSI targets while the server is running

Tal Aloni 8 tahun lalu
induk
melakukan
8d6f7832e6

+ 4 - 16
ISCSI/ISCSI.Server/ISCSIServer.Login.cs

@@ -87,16 +87,16 @@ namespace ISCSI.Server
                     if (request.LoginParameters.ContainsKey("TargetName"))
                     {
                         string targetName = request.LoginParameters.ValueOf("TargetName");
-                        int targetIndex = GetTargetIndex(m_targets, targetName);
-                        if (targetIndex >= 0)
+                        ISCSITarget target = m_targets.FindTarget(targetName);
+                        if (target != null)
                         {
-                            session.Target = m_targets[targetIndex];
-                            if (!session.Target.AuthorizeInitiator(connection.InitiatorName, connection.InitiatorEndPoint))
+                            if (!target.AuthorizeInitiator(connection.InitiatorName, connection.InitiatorEndPoint))
                             {
                                 Log(Severity.Warning, "[{0}] Initiator was not authorized to access {1}", connectionIdentifier, targetName);
                                 response.Status = LoginResponseStatusName.AuthorizationFailure;
                                 return response;
                             }
+                            session.Target = target;
                         }
                         else
                         {
@@ -165,18 +165,6 @@ namespace ISCSI.Server
             return response;
         }
 
-        private static int GetTargetIndex(List<ISCSITarget> targets, string targetName)
-        {
-            for (int index = 0; index < targets.Count; index++)
-            {
-                if (String.Equals(targets[index].TargetName, targetName, StringComparison.InvariantCultureIgnoreCase))
-                {
-                    return index;
-                }
-            }
-            return -1;
-        }
-
         private static void UpdateOperationalParameters(KeyValuePairList<string, string> loginParameters, ISCSISession session, ConnectionParameters connectionParameters)
         {
             string value = loginParameters.ValueOf("MaxRecvDataSegmentLength");

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

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

+ 17 - 5
ISCSI/ISCSI.Server/ISCSIServer.cs

@@ -23,23 +23,23 @@ namespace ISCSI.Server
         public const int DefaultPort = 3260;
 
         private IPEndPoint m_listenerEP;
-        private List<ISCSITarget> m_targets;
 
         private Socket m_listenerSocket;
         private bool m_listening;
+        private TargetList m_targets = new TargetList();
         private SessionManager m_sessionManager = new SessionManager();
         private ConnectionManager m_connectionManager = new ConnectionManager();
 
         public event EventHandler<LogEntry> OnLogEntry;
         
-        public ISCSIServer(List<ISCSITarget> targets) : this(targets, DefaultPort)
+        public ISCSIServer() : this(DefaultPort)
         { }
 
         /// <summary>
         /// Server needs to be started with Start()
         /// </summary>
         /// <param name="port">The port on which the iSCSI server will listen</param>
-        public ISCSIServer(List<ISCSITarget> targets, int port) : this(targets, new IPEndPoint(IPAddress.Any, port))
+        public ISCSIServer(int port) : this(new IPEndPoint(IPAddress.Any, port))
         {
         }
 
@@ -47,10 +47,22 @@ namespace ISCSI.Server
         /// Server needs to be started with Start()
         /// </summary>
         /// <param name="listenerEP">The endpoint on which the iSCSI server will listen</param>
-        public ISCSIServer(List<ISCSITarget> targets, IPEndPoint listenerEP)
+        public ISCSIServer(IPEndPoint listenerEP)
         {
             m_listenerEP = listenerEP;
-            m_targets = targets;
+        }
+
+        public void AddTarget(ISCSITarget target)
+        {
+            m_targets.AddTarget(target);
+        }
+
+        public void AddTargets(List<ISCSITarget> targets)
+        {
+            foreach (ISCSITarget target in targets)
+            {
+                m_targets.AddTarget(target);
+            }
         }
 
         public void Start()

+ 65 - 0
ISCSI/ISCSI.Server/TargetList.cs

@@ -0,0 +1,65 @@
+/* Copyright (C) 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 System.Threading;
+
+namespace ISCSI.Server
+{
+    internal class TargetList
+    {
+        public object Lock = new object();
+        private List<ISCSITarget> m_targets = new List<ISCSITarget>();
+
+        public void AddTarget(ISCSITarget target)
+        {
+            lock (Lock)
+            {
+                int index = IndexOfTarget(target.TargetName);
+                if (index >= 0)
+                {
+                    throw new ArgumentException("A target with the same iSCSI Target Name already exists");
+                }
+                m_targets.Add(target);
+            }
+        }
+
+        public ISCSITarget FindTarget(string targetName)
+        {
+            lock (Lock)
+            {
+                int index = IndexOfTarget(targetName);
+                if (index >= 0)
+                {
+                    return m_targets[index];
+                }
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Caller MUST obtain a lock on TargetList.Lock before calling this method
+        /// </summary>
+        public List<ISCSITarget> GetList()
+        {
+            return new List<ISCSITarget>(m_targets);
+        }
+
+        private int IndexOfTarget(string targetName)
+        {
+            for (int index = 0; index < m_targets.Count; index++)
+            {
+                if (String.Equals(m_targets[index].TargetName, targetName, StringComparison.OrdinalIgnoreCase))
+                {
+                    return index;
+                }
+            }
+            return -1;
+        }
+    }
+}

+ 1 - 0
ISCSI/ISCSI.csproj

@@ -77,6 +77,7 @@
     <Compile Include="ISCSI.Server\PDUHelper.cs" />
     <Compile Include="ISCSI.Server\ServerResponseHelper.cs" />
     <Compile Include="ISCSI.Server\SessionManager.cs" />
+    <Compile Include="ISCSI.Server\TargetList.cs" />
     <Compile Include="ISCSI.Server\TargetResponseHelper.cs" />
     <Compile Include="SCSI\Enums\AddressingMethod.cs" />
     <Compile Include="SCSI\Enums\ModePageCodeName.cs" />

+ 2 - 1
ISCSIConsole/Program.StartCommand.cs

@@ -45,7 +45,8 @@ namespace ISCSIConsole
                     {
                         logFile = parameters.ValueOf("log");
                     }
-                    m_server = new ISCSIServer(m_targets, port);
+                    m_server = new ISCSIServer(port);
+                    m_server.AddTargets(m_targets);
                     m_server.OnLogEntry += new EventHandler<LogEntry>(OnLogEntry);
                     if (logFile != String.Empty)
                     {