public static void CreateVDisk(KeyValuePairList <string, string> parameters)
        {
            if (!VerifyParameters(parameters, "file", "size"))
            {
                Console.WriteLine();
                Console.WriteLine("Invalid parameter.");
                HelpCreate();
                return;
            }

            long sizeInBytes;

            if (parameters.ContainsKey("size"))
            {
                long requestedSizeInMB = Conversion.ToInt64(parameters.ValueOf("size"), 0);
                sizeInBytes = requestedSizeInMB * 1024 * 1024;
                if (requestedSizeInMB <= 0)
                {
                    Console.WriteLine("Invalid size (must be specified in MB).");
                    return;
                }
            }
            else
            {
                Console.WriteLine("The SIZE parameter must be specified.");
                return;
            }

            if (parameters.ContainsKey("file"))
            {
                string path = parameters.ValueOf("file");

                if (new FileInfo(path).Exists)
                {
                    Console.WriteLine("Error: file already exists.");
                    return;
                }

                try
                {
                    m_selectedDisk = VirtualHardDisk.Create(path, sizeInBytes);
                    Console.WriteLine("The virtual disk file was created successfully.");
                }
                catch (IOException)
                {
                    Console.WriteLine("Error: Could not write the virtual disk file.");
                    return;
                }
                catch (UnauthorizedAccessException)
                {
                    Console.WriteLine("Error: Access Denied, Could not write the virtual disk file.");
                    return;
                }
            }
            else
            {
                Console.WriteLine("The FILE parameter was not specified.");
            }
        }
        public static void StartCommand(string[] args)
        {
            if (m_server == null)
            {
                if (m_targets.Count > 0)
                {
                    KeyValuePairList <string, string> parameters = ParseParameters(args, 1);
                    if (!VerifyParameters(parameters, "port", "log"))
                    {
                        Console.WriteLine();
                        Console.WriteLine("Invalid parameter");
                        HelpStart();
                        return;
                    }

                    int port = DefaultISCSIPort;
                    if (parameters.ContainsKey("port"))
                    {
                        port = Conversion.ToInt32(parameters.ValueOf("port"), DefaultISCSIPort);
                    }
                    string logFile = String.Empty;
                    if (parameters.ContainsKey("log"))
                    {
                        logFile = parameters.ValueOf("log");
                    }
                    m_server = new ISCSIServer(m_targets, port, logFile);
                    try
                    {
                        ISCSIServer.Log("Starting Server");
                    }
                    catch (IOException)
                    {
                        Console.WriteLine("Could not append to log file");
                        return;
                    }

                    try
                    {
                        m_server.Start();
                        Console.WriteLine("Server started, listening on port {0}", port);
                    }
                    catch (SocketException)
                    {
                        Console.WriteLine("Could not start iSCSI server");
                        m_server.Stop();
                        m_server = null;
                    }
                }
                else
                {
                    Console.WriteLine("No disks have been attached");
                }
            }
        }
示例#3
0
        public static void AttachISCSIDisk(Disk disk, string defaultTargetName, KeyValuePairList <string, string> parameters)
        {
            if (VerifyParameters(parameters, "readonly", "target"))
            {
                bool isReadOnly = parameters.ContainsKey("readonly");
                disk.IsReadOnly |= isReadOnly;
                if (disk is DiskImage)
                {
                    bool isLocked = ((DiskImage)disk).ExclusiveLock();
                    if (!isLocked)
                    {
                        Console.WriteLine("Error: Cannot lock the disk image for exclusive access");
                        return;
                    }
                }

                ISCSITarget target     = null;
                string      targetName = defaultTargetName;
                if (parameters.ContainsKey("target"))
                {
                    string name = parameters.ValueOf("target");
                    if (IsValidISCSIName(name))
                    {
                        targetName = name;
                    }
                    else if (IsValidStorageTargetName(name))
                    {
                        targetName = DefaultTargetIQN + ":" + name;
                    }
                    else
                    {
                        Console.WriteLine("Invalid parameter.");
                        HelpAttach();
                    }
                }

                target = FindTarget(targetName);

                if (target == null)
                {
                    target = AddTarget(targetName);
                }

                target.Disks.Add(disk);
                Console.WriteLine("Disk added to target: {0}", target.TargetName);
            }
            else
            {
                HelpAttach();
            }
        }
示例#4
0
        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);
        }
示例#5
0
        public static void SelectCommand(string[] args)
        {
            if (args.Length == 1)
            {
                HelpSelect();
                return;
            }

            switch (args[1].ToLower())
            {
            case "disk":
            {
                if (args.Length == 3)
                {
                    int diskIndex = Conversion.ToInt32(args[2], -1);
                    if (diskIndex >= 0)
                    {
                        PhysicalDisk disk = null;
                        try
                        {
                            disk = new PhysicalDisk(diskIndex);
                        }
                        catch
                        {
                            Console.WriteLine();
                            Console.WriteLine("Error: Invalid disk number");
                        }

                        if (disk != null)
                        {
                            m_selectedDisk = disk;
                        }
                    }
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("Error: Invalid number of arguments");
                }
                break;
            }

            case "vdisk":
            {
                if (args.Length == 3)
                {
                    KeyValuePairList <string, string> parameters = ParseParameters(args, 2);
                    if (parameters.ContainsKey("file"))
                    {
                        string path = parameters.ValueOf("file");
                        if (new FileInfo(path).Exists)
                        {
                            try
                            {
                                m_selectedDisk = DiskImage.GetDiskImage(path);
                            }
                            catch (InvalidDataException)
                            {
                                Console.WriteLine("Invalid virtual disk format");
                            }
                            catch (NotImplementedException)
                            {
                                Console.WriteLine("Unsupported virtual disk format");
                            }
                            catch (IOException ex)
                            {
                                Console.WriteLine("Cannot read file: " + ex.Message);
                            }
                        }
                        else
                        {
                            Console.WriteLine("File not found: \"{0}\"", path);
                        }
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.WriteLine("Error: Invalid argument");
                    }
                }
                else
                {
                    Console.WriteLine("Error: Invalid number of arguments");
                }
                break;
            }

            case "partition":
            {
                if (m_selectedDisk != null)
                {
                    if (args.Length == 3)
                    {
                        int partitionIndex          = Conversion.ToInt32(args[2], -1);
                        List <Partition> partitions = BasicDiskHelper.GetPartitions(m_selectedDisk);
                        if (partitionIndex >= 0 && partitionIndex < partitions.Count)
                        {
                            m_selectedVolume = partitions[partitionIndex];
                        }
                        else
                        {
                            Console.WriteLine("Error: Invalid partition number");
                        }
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.WriteLine("Error: Partition number was not specified");
                    }
                }
                else
                {
                    Console.WriteLine("No disk has been selected");
                }
                break;
            }

            case "volume":
            {
                if (args.Length == 3)
                {
                    List <Volume> volumes;
                    try
                    {
                        volumes = WindowsVolumeHelper.GetVolumes();
                    }
                    catch
                    {
                        volumes = new List <Volume>();
                    }

                    int volumeIndex = Conversion.ToInt32(args[2], -1);
                    if (volumeIndex >= 0 && volumeIndex < volumes.Count)
                    {
                        m_selectedVolume = volumes[volumeIndex];
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.WriteLine("Error: Invalid volume number");
                    }
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine("Error: Volume number was not specified");
                }
                break;
            }

            default:
                HelpSelect();
                break;
            }
        }
示例#6
0
        private LoginResponseStatusName SetUpSession(LoginRequestPDU request, KeyValuePairList <string, string> requestParameters, ConnectionParameters connection)
        {
            string initiatorName = requestParameters.ValueOf("InitiatorName");

            if (String.IsNullOrEmpty(initiatorName))
            {
                // RFC 3720: InitiatorName: The initiator of the TCP connection MUST provide this key [..]
                // at the first Login of the Login Phase for every connection.
                string loginIdentifier = String.Format("ISID={0},TSIH={1},CID={2}", request.ISID.ToString("x"), request.TSIH.ToString("x"), request.CID.ToString("x"));
                Log(Severity.Warning, "[{0}] Initiator error: InitiatorName was not included in the login request", loginIdentifier);
                return(LoginResponseStatusName.InitiatorError);
            }

            if (request.TSIH == 0)
            {
                // Note: An initiator could login with the same ISID to a different target (another session),
                // We should only perform session reinstatement when an initiator is logging in to the same target.

                // For a new session, the request TSIH is zero,
                // As part of the response, the target generates a TSIH.
                connection.Session = m_sessionManager.StartSession(initiatorName, request.ISID);
                connection.CID     = request.CID;
                Log(Severity.Verbose, "[{0}] Session has been started", connection.Session.SessionIdentifier);
                connection.Session.CommandNumberingStarted = true;
                connection.Session.ExpCmdSN = request.CmdSN;

                string sessionType = requestParameters.ValueOf("SessionType");
                if (sessionType == "Discovery")
                {
                    connection.Session.IsDiscovery = true;
                }
                else //sessionType == "Normal" or unspecified (default is Normal)
                {
                    if (requestParameters.ContainsKey("TargetName"))
                    {
                        string targetName = requestParameters.ValueOf("TargetName");
                        return(SetUpNormalSession(request, targetName, connection));
                    }
                    else
                    {
                        // RFC 3720: For any connection within a session whose type is not "Discovery", the first Login Request MUST also include the TargetName key=value pair.
                        Log(Severity.Warning, "[{0}] Initiator error: TargetName was not included in a non-discovery session", connection.ConnectionIdentifier);
                        return(LoginResponseStatusName.InitiatorError);
                    }
                }
            }
            else
            {
                ISCSISession existingSession = m_sessionManager.FindSession(initiatorName, request.ISID, request.TSIH);
                if (existingSession == null)
                {
                    return(LoginResponseStatusName.SessionDoesNotExist);
                }
                else
                {
                    connection.Session = existingSession;
                    ConnectionState existingConnection = m_connectionManager.FindConnection(existingSession, request.CID);
                    if (existingConnection != null)
                    {
                        // do connection reinstatement
                        Log(Severity.Verbose, "[{0}] Initiating implicit logout", existingConnection.ConnectionIdentifier);
                        m_connectionManager.ReleaseConnection(existingConnection);
                    }
                    else
                    {
                        // add a new connection to the session
                        if (m_connectionManager.GetSessionConnections(existingSession).Count > existingSession.MaxConnections)
                        {
                            return(LoginResponseStatusName.TooManyConnections);
                        }
                    }
                    connection.CID = request.CID;
                }
            }
            return(LoginResponseStatusName.Success);
        }
示例#7
0
        public static void AttachCommand(string[] args)
        {
            if (m_server != null)
            {
                Console.WriteLine("Server is already running");
                return;
            }

            if (args.Length >= 2)
            {
                KeyValuePairList <string, string> parameters = ParseParameters(args, 2);
                if (!VerifyParameters(parameters, "vdisk", "disk", "volume", "readonly", "target"))
                {
                    Console.WriteLine();
                    Console.WriteLine("Invalid parameter");
                    HelpAttach();
                    return;
                }

                switch (args[1].ToLower())
                {
                case "vdisk":
                {
                    if (m_selectedDisk == null)
                    {
                        Console.WriteLine("No disk has been selected");
                        break;
                    }

                    if (!(m_selectedDisk is DiskImage))
                    {
                        Console.WriteLine("Selected disk is not a disk image");
                        break;
                    }

                    DiskImage disk = (DiskImage)m_selectedDisk;
                    string    defaultStorageTargetName = Path.GetFileNameWithoutExtension(disk.Path);
                    string    defaultTargetName        = DefaultTargetIQN + ":" + defaultStorageTargetName.Replace(" ", ""); // spaces are not allowed
                    AttachISCSIDisk(disk, defaultTargetName, parameters);
                    break;
                }

                case "disk":
                {
                    if (m_selectedDisk == null)
                    {
                        Console.WriteLine("Error: No disk has been selected.");
                        break;
                    }

                    if (!(m_selectedDisk is PhysicalDisk))
                    {
                        Console.WriteLine("Error: The selected disk is not a physical disk.");
                        break;
                    }

                    bool         isAttachmentReadOnly = parameters.ContainsKey("readonly");
                    PhysicalDisk disk = (PhysicalDisk)m_selectedDisk;
                    if (!isAttachmentReadOnly)
                    {
                        if (Environment.OSVersion.Version.Major >= 6)
                        {
                            bool isDiskReadOnly;
                            bool isOnline = disk.GetOnlineStatus(out isDiskReadOnly);
                            if (isOnline)
                            {
                                Console.WriteLine();
                                Console.WriteLine("Error: The selected disk must be taken offline.");
                                break;
                            }

                            if (!isAttachmentReadOnly && isDiskReadOnly)
                            {
                                Console.WriteLine();
                                Console.WriteLine("Error: The selected disk is set to readonly!");
                                break;
                            }
                        }
                        else
                        {
                            Console.WriteLine();
                            // Locking mechanism is not implemented
                            Console.Write("Warning: if a volume on this disk is mounted locally, data corruption may occur!");
                        }
                    }
                    string defaultStorageTargetName = string.Format("disk{0}", disk.PhysicalDiskIndex);
                    string defaultTargetName        = DefaultTargetIQN + ":" + defaultStorageTargetName;
                    AttachISCSIDisk(disk, defaultTargetName, parameters);
                    break;
                }

                case "volume":
                {
                    if (m_selectedVolume == null)
                    {
                        Console.WriteLine("No volume has been selected.");
                        break;
                    }

                    VolumeDisk virtualDisk          = new VolumeDisk(m_selectedVolume);
                    string     defaultTargetName    = DefaultTargetIQN + ":Volume";
                    bool       isAttachmentReadOnly = parameters.ContainsKey("readonly");
                    if (!isAttachmentReadOnly)
                    {
                        if (Environment.OSVersion.Version.Major >= 6)
                        {
                            if (m_selectedVolume is DynamicVolume)
                            {
                                foreach (DiskExtent extent in ((DynamicVolume)m_selectedVolume).Extents)
                                {
                                    if (extent.Disk is PhysicalDisk)
                                    {
                                        bool isDiskReadOnly;
                                        bool isOnline = ((PhysicalDisk)extent.Disk).GetOnlineStatus(out isDiskReadOnly);
                                        if (isOnline)
                                        {
                                            Console.WriteLine("Error: All disks containing the volume must be taken offline.");
                                            return;
                                        }

                                        if (isDiskReadOnly)
                                        {
                                            Console.WriteLine("Error: A disk containing the volume is set to readonly.");
                                            return;
                                        }
                                    }
                                }
                            }
                            else if (m_selectedVolume is Partition)
                            {
                                Disk disk = ((Partition)m_selectedVolume).Disk;
                                if (disk is PhysicalDisk)
                                {
                                    bool isDiskReadOnly;
                                    bool isOnline = ((PhysicalDisk)disk).GetOnlineStatus(out isDiskReadOnly);

                                    if (isOnline)
                                    {
                                        Console.WriteLine("Error: The disk containing the volume must be taken offline.");
                                        return;
                                    }

                                    if (isDiskReadOnly)
                                    {
                                        Console.WriteLine("Error: The disk containing the volume is set to readonly.");
                                        return;
                                    }
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine();
                            // Locking mechanism is not implemented
                            Console.WriteLine("Warning: if this volume is mounted locally, data corruption may occur!");
                        }
                    }
                    AttachISCSIDisk(virtualDisk, defaultTargetName, parameters);
                    break;
                }

                default:
                {
                    Console.WriteLine();
                    Console.WriteLine("Invalid argument.");
                    HelpAttach();
                    break;
                }
                }
            }
            else
            {
                HelpAttach();
            }
        }
        public static void SetCommand(string[] args)
        {
            if (args.Length == 2)
            {
                KeyValuePairList <string, string> parameters = ParseParameters(args, 1);
                if (!VerifyParameters(parameters, "debug", "commandqueue", "MaxRecvDataSegmentLength".ToLower(), "MaxBurstLength".ToLower(), "FirstBurstLength".ToLower()))
                {
                    Console.WriteLine("Invalid parameter.");
                    return;
                }

                if (parameters.ContainsKey("debug"))
                {
                    m_debug = true;
                }

                if (parameters.ContainsKey("CommandQueue".ToLower()))
                {
                    int requestedCommandQueueSize = Conversion.ToInt32(parameters.ValueOf("commandqueue"), 0);
                    if (requestedCommandQueueSize < 0)
                    {
                        Console.WriteLine("Invalid queue size (must be non-negative).");
                        return;
                    }

                    SessionParameters.DefaultCommandQueueSize = (uint)requestedCommandQueueSize;
                }

                if (parameters.ContainsKey("MaxRecvDataSegmentLength".ToLower()))
                {
                    int requestedMaxRecvDataSegmentLength = Conversion.ToInt32(parameters.ValueOf("MaxRecvDataSegmentLength".ToLower()), 0);
                    if (requestedMaxRecvDataSegmentLength <= 0)
                    {
                        Console.WriteLine("Invalid length (must be positive).");
                        return;
                    }

                    ConnectionParameters.DeclaredMaxRecvDataSegmentLength = requestedMaxRecvDataSegmentLength;
                    Console.WriteLine("MaxRecvDataSegmentLength has been set to " + ISCSIServer.OfferedMaxBurstLength);
                }

                if (parameters.ContainsKey("MaxBurstLength".ToLower()))
                {
                    int requestedMaxBurstLength = Conversion.ToInt32(parameters.ValueOf("MaxBurstLength".ToLower()), 0);
                    if (requestedMaxBurstLength <= 0)
                    {
                        Console.WriteLine("Invalid length (must be positive).");
                        return;
                    }

                    ISCSIServer.OfferedMaxBurstLength = requestedMaxBurstLength;
                    Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.OfferedMaxBurstLength);
                    if (ISCSIServer.OfferedMaxBurstLength < ISCSIServer.OfferedFirstBurstLength)
                    {
                        // FirstBurstLength MUST NOT exceed MaxBurstLength
                        ISCSIServer.OfferedFirstBurstLength = ISCSIServer.OfferedMaxBurstLength;
                        Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.OfferedFirstBurstLength);
                    }
                }

                if (parameters.ContainsKey("FirstBurstLength".ToLower()))
                {
                    int requestedFirstBurstLength = Conversion.ToInt32(parameters.ValueOf("FirstBurstLength".ToLower()), 0);
                    if (requestedFirstBurstLength <= 0)
                    {
                        Console.WriteLine("Invalid length (must be positive).");
                        return;
                    }

                    ISCSIServer.OfferedFirstBurstLength = requestedFirstBurstLength;
                    Console.WriteLine("Offered FirstBurstLength has been set to " + ISCSIServer.OfferedFirstBurstLength);
                    if (ISCSIServer.OfferedMaxBurstLength < ISCSIServer.OfferedFirstBurstLength)
                    {
                        // FirstBurstLength MUST NOT exceed MaxBurstLength
                        ISCSIServer.OfferedMaxBurstLength = ISCSIServer.OfferedFirstBurstLength;
                        Console.WriteLine("Offered MaxBurstLength has been set to " + ISCSIServer.OfferedMaxBurstLength);
                    }
                }
            }
            else if (args.Length > 2)
            {
                Console.WriteLine("Too many arguments.");
                HelpSet();
            }
            else
            {
                HelpSet();
            }
        }