- /*
- * Created with SharpDevelop
- *
- * User: Jimmy Dansbo
- * Email: jimmy at dansbo.dk
- * Date: 26-02-2010
- *
- * Description:
- * Basic wrap for iscsidsc.dll (Microsoft iSCSI Initiator)
- *
- * History:
- * 01-03-2010: Changed ReportActiveTargetMappings to use the correct
- * structure instead of searching through a byte array
- * to find the information needed.
- * Created BuffToTargetMapping function
- * Changed BuffToPortalInfo function to make it more streamlined
- * 02-03-2010: Added InitiatorExists and InitiatorStarted functions.
- * 25-06-2011: Added GetErrDef function.
- */
- using System;
- using System.ServiceProcess;
- using System.Runtime.InteropServices;
- namespace iSCSI
- {
- // Below are two classes. One wraps the iscsidsc.dll and provides
- // the most basic functions directly from the dll.
- // The other class is a series of functions created for csharp, you
- // could say that they wrap the c++ functions to make it easier to
- // call the iscsi library from normal csharp code
- public class DLLwrap {
- // First we have some constants used throughout the code.
- // These constants are translated from iscsidsc.h
- // #define MAX_ISCSI_PORTAL_NAME_LEN 256
- public const ushort MAX_ISCSI_PORTAL_NAME_LEN = 256;
- // #define MAX_ISCSI_PORTAL_ADDRESS_LEN 256
- public const ushort MAX_ISCSI_PORTAL_ADDRESS_LEN = 256;
- // #define MAX_ISCSI_NAME_LEN 223
- public const ushort MAX_ISCSI_NAME_LEN = 223;
- // #define MAX_ISCSI_HBANAME_LEN 256
- public const ushort MAX_ISCSI_HBANAME_LEN = 256;
- // #define ISCSI_ALL_INITIATOR_PORTS ((ULONG)-1)
- public const UInt32 ISCSI_ALL_INITIATOR_PORTS = 4294967295;
- // #define ISCSI_ANY_INITIATOR_PORT ((ULONG)-1)
- public const UInt32 ISCSI_ANY_INITIATOR_PORT = 4294967295;
- // Below contant is the size of the ISCSI_TARGET_PORTAL_INFO
- // structure which means that it is equal to:
- // MAX_ISCSI_HBANAME_LEN +
- // Size of UInt32 = 4 +
- // MAX_ISCSI_PORTAL_NAME_LEN +
- // MAX_ISCSI_PORTAL_ADDRESS_LEN +
- // Size of ushort = 2 +
- // (dont know why) 2
- // I do not know why the last two bytes are there making the
- // size 776 bytes instead of 774 bytes, but I found that the
- // structure returned is actually 776 bytes long ????
- public const int ISCSI_TARGET_PORTAL_INFO_SIZE = 776;
- // According to MS SDK the MAX_PATH constant is defined as
- // 260 bytes allthough it is possible to work with longer
- // paths in which case MAX_PATH is 32767 bytes.
- // I am guessing that we are only using the short version
- // when working with the iSCSI initiator
- public const int MAX_PATH = 264;
- // Below constants are here to ensure that we use the same
- // data type in csharp as is used in c++. It is possible
- // that a normal csharp bool would work just as well.
- public const byte TRUE = 1;
- public const byte FALSE = 0;
- // Next we have some structures used by the functions in
- // iscsidsc.dll I have tried to convert them from c++ to
- // csharp as best I could. All information about the
- // structures have also been taken from iscsidsc.h
- // typedef struct
- // {
- // ULONG MajorVersion;
- // ULONG MinorVersion;
- // ULONG BuildNumber;
- // } ISCSI_VERSION_INFO, *PISCSI_VERSION_INFO;
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_VERSION_INFO {
- public UInt32 MajorVersion;
- public UInt32 MinorVersion;
- public UInt32 BuildNumber;
- }
- // Notice that the name of the struct in c++ is not the
- // same as the name I have used in csharp. This is
- // because the c++ headerfile also has type definitions
- // for unicode ??? I have used the "normal" definitions
- // typedef struct
- // {
- // CHAR SymbolicName[MAX_ISCSI_PORTAL_NAME_LEN];
- // CHAR Address[MAX_ISCSI_PORTAL_ADDRESS_LEN];
- // USHORT Socket;
- // } ISCSI_TARGET_PORTALA, *PISCSI_TARGET_PORTALA;
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_TARGET_PORTAL {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_NAME_LEN)]
- public byte[] SymbolicName;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_ADDRESS_LEN)]
- public byte[] Address;
- public ushort Socket;
- }
- // Each iscsi session and connection has a unique session or connection
- // id that is used to reference the session. It it not related to the
- // actual ISID
- // typedef struct _ISCSI_UNIQUE_SESSION_ID
- // {
- // ULONGLONG AdapterUnique;
- // ULONGLONG AdapterSpecific;
- // } ISCSI_UNIQUE_SESSION_ID, *PISCSI_UNIQUE_SESSION_ID,
- // ISCSI_UNIQUE_CONNECTION_ID, *PISCSI_UNIQUE_CONNECTION_ID;
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_UNIQUE_SESSION_ID {
- public UInt64 AdapterUnique;
- public UInt64 AdapterSpecific;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_UNIQUE_CONNECTION_ID {
- public UInt64 AdapterUnique;
- public UInt64 AdapterSpecific;
- }
- // typedef struct
- // {
- // CHAR InitiatorName[MAX_ISCSI_HBANAME_LEN];
- // ULONG InitiatorPortNumber;
- // CHAR SymbolicName[MAX_ISCSI_PORTAL_NAME_LEN];
- // CHAR Address[MAX_ISCSI_PORTAL_ADDRESS_LEN];
- // USHORT Socket;
- // } ISCSI_TARGET_PORTAL_INFOA, *PISCSI_TARGET_PORTAL_INFOA;
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_TARGET_PORTAL_INFO {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_HBANAME_LEN)]
- public byte[] InitiatorName;
- public UInt32 InitiatorPortNumber;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_NAME_LEN)]
- public byte[] SymbolicName;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_ADDRESS_LEN)]
- public byte[] Address;
- public ushort Socket;
- }
- // typedef struct
- // {
- // ULONG OSLUN;
- // ULONGLONG TargetLUN;
- // } SCSI_LUN_LIST, *PISCSI_LUN_LIST;
- [StructLayout(LayoutKind.Sequential)]
- public struct SCSI_LUN_LIST {
- public UInt32 OSLUN;
- public UInt64 TargetLUN;
- }
- // typedef struct
- // {
- // CHAR InitiatorName[MAX_ISCSI_HBANAME_LEN];
- // CHAR TargetName[MAX_ISCSI_NAME_LEN + 1];
- // CHAR OSDeviceName[MAX_PATH]; /* \device\ScsiPort3 */
- // ISCSI_UNIQUE_SESSION_ID SessionId;
- // ULONG OSBusNumber;
- // ULONG OSTargetNumber;
- // ULONG LUNCount;
- // #ifdef MIDL_PASS
- // [size_is(LUNCount)]
- // #endif
- // PSCSI_LUN_LIST LUNList;
- // } ISCSI_TARGET_MAPPINGA, *PISCSI_TARGET_MAPPINGA;
- [StructLayout(LayoutKind.Sequential)]
- public struct ISCSI_TARGET_MAPPING {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_HBANAME_LEN)]
- public byte[] InitiatorName;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_NAME_LEN+1)]
- public byte[] TargetName;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_PATH)]
- public byte[] OSDeviceName;
- public ISCSI_UNIQUE_SESSION_ID SessionId;
- public Int32 OSBusNumber;
- public Int32 OSTargetNumber;
- public Int32 LUNCount;
- public IntPtr LUNList;
- }
- // Last we have the actual functions referenced directly from
- // the iscsidsc.dll file. Again I have tried to create the
- // functions as close to the c++ definition as possible
- // ISDSC_STATUS ISDSC_API GetIScsiInitiatorNodeNameA(
- // __out_ecount(MAX_ISCSI_NAME_LEN+1) PCHAR InitiatorNodeName
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- GetIScsiInitiatorNodeName(byte[] NodeName);
- // ISDSC_STATUS ISDSC_API GetIScsiVersionInformation(
- // PISCSI_VERSION_INFO VersionInfo
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- GetIScsiVersionInformation(ref ISCSI_VERSION_INFO VersionInfo);
- // ISDSC_STATUS ISDSC_API AddIScsiSendTargetPortalA(
- // IN OPTIONAL __in_opt PCHAR InitiatorInstance,
- // IN OPTIONAL ULONG InitiatorPortNumber,
- // IN OPTIONAL PISCSI_LOGIN_OPTIONS LoginOptions,
- // IN OPTIONAL ISCSI_SECURITY_FLAGS SecurityFlags,
- // IN PISCSI_TARGET_PORTALA Portal
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- AddIScsiSendTargetPortal(byte[] InitiatorName,
- UInt32 InitiatorPortNumber,
- byte[] LoginOptions,
- UInt64 SecurityFlags,
- ref ISCSI_TARGET_PORTAL Portal);
- // ISDSC_STATUS ISDSC_API RemoveIScsiSendTargetPortalA(
- // IN OPTIONAL PCHAR __in_opt InitiatorInstance,
- // IN OPTIONAL ULONG InitiatorPortNumber,
- // IN PISCSI_TARGET_PORTALA Portal
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- RemoveIScsiSendTargetPortal(byte[] InitiatorInstance,
- UInt32 InitiatorPortNumber,
- ref ISCSI_TARGET_PORTAL Portal);
- // ISDSC_STATUS ISDSC_API ReportIScsiSendTargetPortalsA(
- // IN OUT PULONG PortalCount,
- // IN OUT PISCSI_TARGET_PORTAL_INFOA PortalInfo
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- ReportIScsiSendTargetPortals(ref UInt32 PortalCount,
- //ref ISCSI_TARGET_PORTAL_INFO PortalInfo);
- byte[] PortalInfo);
- // ISDSC_STATUS ISDSC_API ReportIScsiTargetsA(
- // IN BOOLEAN ForceUpdate,
- // IN OUT PULONG BufferSize,
- // OUT __inout_ecount_opt(*BufferSize) PCHAR Buffer
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- ReportIScsiTargets(byte ForceUpdate,
- ref UInt32 BufferSize,
- byte[] Buffer);
- // ISDSC_STATUS ISDSC_API LoginIScsiTargetA(
- // IN PCHAR __in TargetName,
- // IN BOOLEAN IsInformationalSession,
- // IN OPTIONAL __in_opt PCHAR InitiatorInstance,
- // IN OPTIONAL ULONG InitiatorPortNumber,
- // IN OPTIONAL PISCSI_TARGET_PORTALA TargetPortal,
- // IN OPTIONAL ISCSI_SECURITY_FLAGS SecurityFlags,
- // IN OPTIONAL PISCSI_TARGET_MAPPINGA Mappings,
- // IN OPTIONAL PISCSI_LOGIN_OPTIONS LoginOptions,
- // IN OPTIONAL ULONG KeySize,
- // IN OPTIONAL __in_ecount_opt(KeySize) PCHAR Key,
- // IN BOOLEAN IsPersistent,
- // OUT PISCSI_UNIQUE_SESSION_ID UniqueSessionId,
- // OUT PISCSI_UNIQUE_CONNECTION_ID UniqueConnectionId
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- LoginIScsiTarget(byte[] TargetName,
- byte IsInformationalSession,
- byte[] InitiatorInstance,
- UInt32 InitiatorPortNumber,
- byte[] TargetPortal,
- UInt64 SecurityFlags,
- byte[] Mappings,
- byte[] LoginOptions,
- UInt32 KeySize,
- byte[] Key,
- byte IsPersistent,
- ref ISCSI_UNIQUE_SESSION_ID UniqueSessionId,
- ref ISCSI_UNIQUE_CONNECTION_ID UniqueConnectionId);
- // ISDSC_STATUS ISDSC_API LogoutIScsiTarget(
- // IN PISCSI_UNIQUE_SESSION_ID UniqueSessionId
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- LogoutIScsiTarget(ref ISCSI_UNIQUE_SESSION_ID UniqueSessionId);
- // ISDSC_STATUS ISDSC_API ReportActiveIScsiTargetMappingsA(
- // IN OUT PULONG BufferSize,
- // OUT PULONG MappingCount,
- // OUT PISCSI_TARGET_MAPPINGA Mappings
- // );
- [DllImport("iscsidsc.dll")]
- public static extern uint
- ReportActiveIScsiTargetMappings(ref UInt32 BufferSize,
- ref UInt32 MappingCount,
- byte[] Mappings);
- }
- public class Funcs {
- // This function will check if the iscsidsc.dll (iSCSI initiator) is
- // found in the system.
- // It returns true if the file is found and false if not
- public static bool InitiatorExists() {
- return (
- System.IO.File.Exists(
- System.Environment.GetEnvironmentVariable("windir")+
- "\\system32\\iscsidsc.dll"));
- }
- // This function will check if the iSCSI Initiator service is started.
- // If it is not started the function will try to start it.
- // The function returns true if the iSCSI Initiator service is started.
- public static bool InitiatorStarted(int SecondsToWait) {
- // Check if the iSCSI service is running
- try {
- sc.ServiceName = "MSiSCSI";
- // the iSCSI server is running we are good to go.
- if (sc.Status == ServiceControllerStatus.Running)
- return (true);
- else {
- // If the iSCSI service is not running, try to start it
- try {
- sc.Start();
- // Wait SecondsToWait for the service to start
- sc.WaitForStatus(ServiceControllerStatus.Running,
- TimeSpan.FromSeconds((double)SecondsToWait));
- // If the service could not start, we return false
- } catch {
- return (false);
- }
- }
- // If the service was not found, we return false
- } catch {
- return (false);
- }
- // If we reach this point the service exists and is started.
- return (true);
- }
- // This function retrieves the iSCSI Initiator Node Name
- // from the iSCSI initiator and returns it in a string
- public static string GetInitiatorNodeName() {
- // Create a buffer that can contain a maximum of
- // MAX_ISCSI_NAME_LEN+1 bytes
- uint Status;
- // If the call to GetIScsiInititatorNodeName returns a
- // value of 0 (zero), it has succeeded and the variable
- // NodeName should contain the name of the Initiator
- if ((Status=DLLwrap.GetIScsiInitiatorNodeName(NodeName))==0) {
- // The GetString function is not designed to work with
- // 0 (null) terminated strings so we need to tell it
- // how many bytes to copy. This is done by finding the
- // first occurence of a 0 (zero).
- int strlen = Array.IndexOf(NodeName, (byte)0);
- // Return the Initiator name as a string
- return (System.Text.Encoding.ASCII.GetString(NodeName, (byte)0, strlen)+"\n");
- } else
- return (GetErrDef(Status)+"\n");
- }
- // This function retrieves the iSCSI Initiator version
- // from the iSCSI initiator and returns it in a string
- public static string GetVersionInformation() {
- DLLwrap.ISCSI_VERSION_INFO VersionInfo =
- uint Status;
- // If the call to GetIScsiVersionInformation returns a
- // value of 0 (zero), it has succeeded and the variable
- // VersionInfo should contain the version of the Initiator
- if ((Status=DLLwrap.GetIScsiVersionInformation(ref VersionInfo))==0)
- // Build a string out of the version information and
- // return it.
- return(VersionInfo.MajorVersion.ToString()+"."+
- VersionInfo.MinorVersion.ToString()+"."+
- VersionInfo.BuildNumber.ToString()+"\n");
- else
- return(GetErrDef(Status)+"\n");
- }
- // This function tries to add a SendTarget Portal to the
- // Initiator. It takes two inputs, Portal and Socket.
- // Portal: A string containing the address of the iSCSI
- // target, normally a FQDN or IP address
- // Socket: The port on the iSCSI target that should be
- // connected to, normally 3260
- public static string AddSendTargetPortal(string Portal, ushort Socket) {
- int cnt; // cnt (counter) is used to copy the Portal string
- uint Status;
- // Create a new instance of the ISCSI_TARGET_PORTAL structure
- DLLwrap.ISCSI_TARGET_PORTAL TargetPortal =
- // Allocate memory for the contained Address
- TargetPortal.Address =
- // Allocate memory for the contained Name
- // allthough it is not used we need to allocate the memory
- // to ensure that the socket value will be in the correct
- // place in memory
- TargetPortal.SymbolicName =
- // Add the socket value to the TargetPortal structure
- TargetPortal.Socket = Socket;
- // Copy the address in Portal to the Address variable of
- // the TargetPortal structure. It is done in this way to
- // ensure that the allocated memory of the Address
- // variable remains the same.
- for (cnt=0; cnt<Portal.Length; cnt++)
- TargetPortal.Address[cnt] = (byte)Portal[cnt];
- TargetPortal.Address[cnt] = (byte)0; // Ensure string is 0 terminated
- // If the call to AddIScsiSendTargetPortal returns 0 (zero) it
- // has succeeded and the Target Portal should have been added.
- // According the the MS SDK documentation the only input that this
- // function needs is the pointer to ISCSI_TARGET_PORTAL, the others
- // are optional. This means that we can use default values.
- // InitiatorName = null
- // InitiatorPortNumber = ISCSI_ALL_INITIATOR_PORTS
- // LoginOptions = null
- // SecurityFlags = 0
- if ((Status=DLLwrap.AddIScsiSendTargetPortal(null,
- DLLwrap.ISCSI_ALL_INITIATOR_PORTS,
- null,
- 0,
- ref TargetPortal))==0)
- return ("Added portal "+Portal+"\n");
- else
- return (GetErrDef(Status)+"\n");
- }
- // This function tries to remove a SendTarget Portal from the
- // Initiator. It takes two inputs, Portal and Socket.
- // Portal: A string containing the address of the iSCSI
- // target, normally a FQDN or IP address
- // Socket: The port on the iSCSI target that was
- // connected to, normally 3260
- public static string RemoveSendTargetPortal(string Portal, ushort Socket) {
- int cnt; // cnt (counter) is used to copy the Portal string
- uint Status;
- // Create a new instance of the ISCSI_TARGET_PORTAL structure
- DLLwrap.ISCSI_TARGET_PORTAL TargetPortal =
- // Allocate memory for the contained Address
- TargetPortal.Address =
- // Allocate memory for the contained Name
- // allthough it is not used we need to allocate the memory
- // to ensure that the socket value will be in the correct
- // place in memory
- TargetPortal.SymbolicName =
- // Add the socket value to the TargetPortal structure
- TargetPortal.Socket = Socket;
- // Copy the address in Portal to the Address variable of
- // the TargetPortal structure. It is done in this way to
- // ensure that the allocated memory of the Address
- // variable remains the same.
- for (cnt=0; cnt<Portal.Length; cnt++)
- TargetPortal.Address[cnt] = (byte)Portal[cnt];
- TargetPortal.Address[cnt] = (byte)0; // Ensure string is 0 terminated
- // If the call to RemoveIScsiSendTargetPortal returns 0 (zero) it
- // has succeeded and the Target Portal should have been added.
- // According the the MS SDK documentation the only input that this
- // function needs is the pointer to ISCSI_TARGET_PORTAL, the others
- // are optional. This means that we can use default values.
- // InitiatorInstance = null
- // InitiatorPortNumber = ISCSI_ALL_INITIATOR_PORTS
- if ((Status=DLLwrap.RemoveIScsiSendTargetPortal(null,
- DLLwrap.ISCSI_ALL_INITIATOR_PORTS,
- ref TargetPortal))==0)
- return ("Removed portal "+Portal+"\n");
- else
- return (GetErrDef(Status)+"\n");
- }
- // This function will copy data from a byte array to a structure of
- // ISCSI_TARGET_PORTAL_INFO.
- // It takes two inputs, a byte array and a starting point in the buffer
- // Buff: byte[] that is allready allocated and filled in
- // Start: the address in the byte array where the structure should start
- // The function returns a filled in ISCSI_TARGET_PORTAL_INFO structure
- // This function has not been made public in the class as the only place
- // it is used so far is within the class.
- static DLLwrap.ISCSI_TARGET_PORTAL_INFO BuffToPortalInfo(byte[] Buff, int Start) {
- return (
- (DLLwrap.ISCSI_TARGET_PORTAL_INFO)Marshal.PtrToStructure(
- Marshal.UnsafeAddrOfPinnedArrayElement(Buff,
- DLLwrap.ISCSI_TARGET_PORTAL_INFO_SIZE*Start),
- // To be honest, I am not exactly sure how or why above code works,
- // but it does.
- }
- // This function tells which Target Portals are allready
- // added to the iSCSI initiator
- public static string ReportSendTargetPortals() {
- string str="";
- uint NumPortals=0, cnt;
- byte[] PortalInfoBuffer;
- DLLwrap.ISCSI_TARGET_PORTAL_INFO PortalInfo;
- // Do an initial call to find out how many portals are allready
- // registered in the iSCSI initiator
- DLLwrap.ReportIScsiSendTargetPortals(ref NumPortals, null);
- // If there are more than 0 portals, retrive the list.
- if (NumPortals > 0) {
- // Allocate memory to hold the list of portals.
- str = NumPortals.ToString()+" portal(s) found\n";
- // Get the list of portals from the iSCSI initiator.
- // The function returns them as an array of
- // ISCSI_TARGET_PORTAL_INFO structures
- // I have not been able to make Csharp work correctly with an
- // array of structures so a byte buffer is used.
- DLLwrap.ReportIScsiSendTargetPortals(ref NumPortals, PortalInfoBuffer);
- // For each portal in the list
- for (cnt=0; cnt<NumPortals; cnt++) {
- // Convert the byte array to a useable structure
- PortalInfo = BuffToPortalInfo(PortalInfoBuffer, (int)cnt);
- // Add the portal address and socket to the returned string
- str += System.Text.Encoding.ASCII.GetString(
- PortalInfo.Address,
- 0,
- Array.IndexOf(PortalInfo.Address, (byte)0));
- str += ", "+PortalInfo.Socket.ToString()+"\n";
- }
- } else str = "No portals found\n";
- return (str);
- }
- // This function reports all targets that the iSCSI initiator
- // has access to. This means that targets from all portals are shown
- public static string ReportTargets() {
- string str="";
- uint BufferSize=0, BuffCnt=0;
- int strlen;
- byte[] Buff;
- // Do an initial call to the function to find the buffersize
- DLLwrap.ReportIScsiTargets(DLLwrap.TRUE, ref BufferSize, null);
- // If BufferSize is larger than 0 it means that we have targets
- if (BufferSize > 0) {
- // Allocate memory for that list of targets
- // If the call to ReportIScsiTargets returns a status of 0 it has
- // succeeded and we can get the targets from the buffer
- if (DLLwrap.ReportIScsiTargets(DLLwrap.TRUE, ref BufferSize, Buff)==0) {
- // The buffer contains a series of 0 terminated strings ending with
- // an extra 0 termination so we should cycle through the buffer
- // untill we hit a 0
- while (Buff[BuffCnt] != (byte)0) {
- // Calculate the length of the first string
- strlen = Array.IndexOf(Buff, (byte)0, (int)BuffCnt)-(int)BuffCnt;
- str += System.Text.Encoding.ASCII.GetString(
- Buff, (int)BuffCnt, strlen)+"\n";
- // Count through the buffer until we find the next 0 termination
- while (Buff[BuffCnt++] != (byte)0);
- }
- // For some reason it seems that the ReportIScsiTargets function
- // wants us to allocate a few bytes in the buffer even though
- // there are no targets so below we check the string that is to
- // be returned. If it does not contain anything it means that
- // there were no targets.
- if (str=="") str = "No targets found\n";
- } else str = "Error - Could not get targets in to buffer\n";
- } else str = "No targets found\n";
- return (str);
- }
- // This function will try to log in to the target specified by
- // TargetName. If it is successfull it will return a string
- // containing the word Success, the target name, the
- // specific adapter session ID and the unique adapter session id
- public static string LoginTarget(string TargetName) {
- string str="";
- uint Status;
- DLLwrap.ISCSI_UNIQUE_SESSION_ID SessionID =
- DLLwrap.ISCSI_UNIQUE_CONNECTION_ID ConnectionID =
- // The LoginIScsiTarget function takes a total of 14 inputs
- // where 11 of those are optional. The only ones that must
- // be specified are TargetName, SessionID and ConnectionID.
- // If the function returns 0 (zero) it has successfully
- // logged in to the specified target.
- if ((Status=DLLwrap.LoginIScsiTarget(
- System.Text.Encoding.ASCII.GetBytes(TargetName),
- DLLwrap.FALSE,null,DLLwrap.ISCSI_ANY_INITIATOR_PORT,
- null,0,null,null,0,null,DLLwrap.FALSE,
- ref SessionID,
- ref ConnectionID))==0) {
- // Create the string that is returned on success
- str += TargetName+",";
- str += SessionID.AdapterUnique.ToString()+",";
- str += SessionID.AdapterSpecific.ToString()+"\n";
- } else str = "Error - Unable to log in to target: "+TargetName+" - "+GetErrDef(Status)+"\n";
- return (str);
- }
- // This function will log out of a specified iSCSI target.
- // TargetName should contain the name of the target that should be logged out.
- public static string LogoutTarget(string TargetName) {
- string str="";
- string Mappings;
- string[] StrArr;
- // Get the active mappings
- Mappings = ReportActiveTargetMappings();
- // If above function has returned a string containing "Error" or
- // "No mappings" we can not continue.
- if (Mappings.Contains("Error") || Mappings.Contains("No mappings"))
- str = "Error - No mapping to "+TargetName+" found\n";
- else {
- // If the TargetName specified is found in the mappings, we can
- // log out of it. Otherwise return an error
- if (Mappings.Contains(TargetName)) {
- // Split the string in to lines containing a single target
- StrArr = Mappings.Split('\n');
- // For each target
- foreach (string tmpstr in StrArr) {
- // If we have found the TargetName that we want
- if (tmpstr.Contains(TargetName)) {
- // Split the string at ',' to get TargetName and
- // SessionID in individual strings.
- StrArr = tmpstr.Split(',');
- // Convert the strings to ISCSI_UNIQUE_SESSION_ID structure
- SessionID.AdapterUnique = System.Convert.ToUInt64(StrArr[1]);
- SessionID.AdapterSpecific = System.Convert.ToUInt64(StrArr[2]);
- // Do the actual log out of the target
- // If LogoutIScsiTarget return 0 (zero) the target has
- // successfully been logged out.
- if (DLLwrap.LogoutIScsiTarget(ref SessionID)==0)
- str = "Success - Logged out of "+TargetName+"\n";
- else
- str = "Error - Unable to log out of "+TargetName+"\n";
- }
- }
- } else str = "Error - No mapping to "+TargetName+" found\n";
- }
- return (str);
- }
- // This function will copy data from a byte array to a structure of
- // ISCSI_TARGET_MAPPING.
- // It takes two inputs, a byte array and a starting point in the buffer
- // Buff: byte[] that is allready allocated and filled in
- // Start: the address in the byte array where the structure should start
- // The function returns a filled in ISCSI_TARGET_MAPPING structure
- // This function has not been made public in the class as the only place
- // it is used so far is within the class.
- static DLLwrap.ISCSI_TARGET_MAPPING BuffToTargetMapping(byte[] Buff, int Start) {
- return (
- (DLLwrap.ISCSI_TARGET_MAPPING)Marshal.PtrToStructure(
- Marshal.UnsafeAddrOfPinnedArrayElement(Buff,
- Start),
- // To be honest, I am not exactly sure how or why above code works,
- // but it does.
- }
- // This function will return a list of active targets from the iSCSI
- // initiator. Returning a list of connected targets with their
- // respective SessionID's.
- public static string ReportActiveTargetMappings() {
- string str="";
- byte[] TargetMapBuffer;
- DLLwrap.ISCSI_TARGET_MAPPING TargetMapping;
- uint BufferSize=0, MappingCount=0;
- int mapcnt;
- // Define the size of the ISCSI_TARGET_MAPPING structure
- int TargetMapSize = DLLwrap.MAX_ISCSI_HBANAME_LEN+
- DLLwrap.MAX_ISCSI_NAME_LEN+1+
- DLLwrap.MAX_PATH+
- 16+ // Size of ISCSI_UNIQUE_SESSION_ID
- // Do an initial call to ReportActiveIScsiTargetMappings to find the
- // buffer size
- DLLwrap.ReportActiveIScsiTargetMappings(ref BufferSize, ref MappingCount, null);
- // If BufferSize is larger than 0, we are connected to targets.
- if (BufferSize > 0) {
- // Allocate memory for the bufferr
- // If the call to ReportActiveIScsiTargetMappings returns
- // 0 (zero) it has succeeded and the buffer is filled with
- // ISCSI_TARGET_MAPPING structures.
- if (DLLwrap.ReportActiveIScsiTargetMappings(ref BufferSize,
- ref MappingCount,
- TargetMapBuffer)==0) {
- // For each mapping the data from the buffer is copied to an
- // ISCSI_TARGET_MAPPING structure
- for (mapcnt=1; mapcnt<=MappingCount; mapcnt++) {
- TargetMapping = BuffToTargetMapping(TargetMapBuffer,
- (mapcnt-1)*TargetMapSize);
- // Copy the target name to the string beeing returned
- str += System.Text.Encoding.ASCII.GetString(
- TargetMapping.TargetName,
- 0,
- Array.IndexOf(TargetMapping.TargetName, (byte)0))+",";
- // Copy the session ID to the string beeing returned.
- str += TargetMapping.SessionId.AdapterUnique.ToString()+",";
- str += TargetMapping.SessionId.AdapterSpecific.ToString()+"\n";
- }
- } else str = "Error - Unable to get target mappings in buffer\n";
- } else str = "No mappings found\n";
- return (str);
- }
- // This function will return a string corresponding to the
- // Status code, as defined in winerror.h
- // As not all error codes has been implemented it will
- // return a general error string with the Status code if
- // it is unable to return the correct error definition.
- // All error codes are copied from:
- // http://msdn.microsoft.com/en-us/library/ms819773.aspx
- static string GetErrDef(uint Status) {
- switch (Status) {
- case 0: return ("NO_ERROR");
- case 1: return ("ERROR_INVALID_FUNCTION");
- case 2: return ("ERROR_FILE_NOT_FOUND");
- case 3: return ("ERROR_PATH_NOT_FOUND");
- case 4: return ("ERROR_TOO_MANY_OPEN_FILES");
- case 5: return ("ERROR_ACCESS_DENIED");
- case 6: return ("ERROR_INVALID_HANDLE");
- case 7: return ("ERROR_ARENA_TRASHED");
- case 8: return ("ERROR_NOT_ENOUGH_MEMORY");
- case 9: return ("ERROR_INVALID_BLOCK");
- case 10: return ("ERROR_BAD_ENVIRONMENT");
- case 11: return ("ERROR_BAD_FORMAT");
- case 12: return ("ERROR_INVALID_ACCESS");
- case 13: return ("ERROR_INVALID_DATA");
- case 14: return ("ERROR_OUTOFMEMORY");
- case 15: return ("ERROR_INVALID_DRIVE");
- case 16: return ("ERROR_CURRENT_DIRECTORY");
- case 17: return ("ERROR_NOT_SAME_DEVICE");
- case 18: return ("ERROR_NO_MORE_FILES");
- case 19: return ("ERROR_WRITE_PROTECT");
- case 20: return ("ERROR_BAD_UNIT");
- case 21: return ("ERROR_NOT_READY");
- case 22: return ("ERROR_BAD_COMMAND");
- case 23: return ("ERROR_CRC");
- case 24: return ("ERROR_BAD_LENGTH");
- case 25: return ("ERROR_SEEK");
- case 26: return ("ERROR_NOT_DOS_DISK");
- case 27: return ("ERROR_SECTOR_NOT_FOUND");
- case 28: return ("ERROR_OUT_OF_PAPER");
- case 29: return ("ERROR_READ_FAULT");
- case 30: return ("ERROR_READ_FAULT");
- default: return ("UNKNOWN - "+Status.ToString());
- }
- }
- }
- }
Recent Pastes