/* Copyright (C) 2012-2017 Tal Aloni . 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.Net; using System.Text; using SCSI; using Utilities; namespace ISCSI.Server { public class ISCSITarget : SCSITargetInterface { private string m_targetName; // ISCSI name public SCSITargetInterface Target { get; } // SCSI events: public event EventHandler OnStandardInquiry; public event EventHandler OnUnitSerialNumberInquiry; public event EventHandler OnDeviceIdentificationInquiry; // iSCSI events: public event EventHandler OnAuthorizationRequest; public event EventHandler OnTextRequest; public event EventHandler OnSessionTermination; public ISCSITarget(string targetName, List disks) : this(targetName, new VirtualSCSITarget(targetName, disks)) { } public ISCSITarget(string targetName, SCSITargetInterface scsiTarget) { m_targetName = targetName; Target = scsiTarget; Target.OnStandardInquiry += new EventHandler(Target_OnStandardInquiry); Target.OnDeviceIdentificationInquiry += new EventHandler(Target_OnDeviceIdentificationInquiry); Target.OnUnitSerialNumberInquiry += new EventHandler(Target_OnUnitSerialNumberInquiry); } public void QueueCommand(byte[] commandBytes, LUNStructure lun, byte[] data, object task, OnCommandCompleted OnCommandCompleted) { Target.QueueCommand(commandBytes, lun, data, task, OnCommandCompleted); } public SCSIStatusCodeName ExecuteCommand(byte[] commandBytes, LUNStructure lun, byte[] data, out byte[] response) { return Target.ExecuteCommand(commandBytes, lun, data, out response); } public void Target_OnStandardInquiry(object sender, StandardInquiryEventArgs args) { args.Data.VersionDescriptors.Add(VersionDescriptorName.iSCSI); // To be thread-safe we must capture the delegate reference first EventHandler handler = OnStandardInquiry; if (handler != null) { handler(this, args); } } void Target_OnUnitSerialNumberInquiry(object sender, UnitSerialNumberInquiryEventArgs args) { // To be thread-safe we must capture the delegate reference first EventHandler handler = OnUnitSerialNumberInquiry; if (handler != null) { handler(this, args); } } public void Target_OnDeviceIdentificationInquiry(object sender, DeviceIdentificationInquiryEventArgs args) { // ISCSI identifier is needed for WinPE to pick up the disk during boot (after iPXE's sanhook) args.Page.IdentificationDescriptorList.Add(IdentificationDescriptor.GetSCSINameStringIdentifier(m_targetName)); // To be thread-safe we must capture the delegate reference first EventHandler handler = OnDeviceIdentificationInquiry; if (handler != null) { handler(this, args); } } internal bool AuthorizeInitiator(string initiatorName, ulong isid, IPEndPoint initiatorEndPoint) { // To be thread-safe we must capture the delegate reference first EventHandler handler = OnAuthorizationRequest; if (handler != null) { AuthorizationRequestArgs args = new AuthorizationRequestArgs(initiatorName, isid, initiatorEndPoint); handler(this, args); return args.Accept; } return true; } internal KeyValuePairList GetTextResponse(KeyValuePairList requestParameters) { EventHandler handler = OnTextRequest; if (handler != null) { TextRequestArgs args = new TextRequestArgs(requestParameters); handler(this, args); return args.ResponseParaemeters; } return new KeyValuePairList(); } internal void NotifySessionTermination(string initiatorName, ulong isid, SessionTerminationReason reason) { EventHandler handler = OnSessionTermination; if (handler != null) { SessionTerminationArgs args = new SessionTerminationArgs(initiatorName, isid, reason); handler(this, args); } } public string TargetName { get { return m_targetName; } } public SCSITargetInterface SCSITarget { get { return Target; } } } }