CSHARP 18
Iscsi.cs By jimmyd on 18th September 2021 07:21:11 AM
  1. /*
  2.  * Created with SharpDevelop
  3.  *
  4.  * User: Jimmy Dansbo
  5.  * Email: jimmy at dansbo.dk
  6.  * Date: 26-02-2010
  7.  *
  8.  * Description:
  9.  *      Basic wrap for iscsidsc.dll (Microsoft iSCSI Initiator)
  10.  *
  11.  * History:
  12.  *      01-03-2010: Changed ReportActiveTargetMappings to use the correct
  13.  *              structure instead of searching through a byte array
  14.  *              to find the information needed.
  15.  *              Created BuffToTargetMapping function
  16.  *              Changed BuffToPortalInfo function to make it more streamlined
  17.  *      02-03-2010: Added InitiatorExists and InitiatorStarted functions.
  18.  *      25-06-2011: Added GetErrDef function.
  19.  */
  20. using System;
  21. using System.ServiceProcess;
  22. using System.Runtime.InteropServices;
  23.  
  24. namespace iSCSI
  25. {
  26.     // Below are two classes. One wraps the iscsidsc.dll and provides
  27.     // the most basic functions directly from the dll.
  28.     // The other class is a series of functions created for csharp, you
  29.     // could say that they wrap the c++ functions to make it easier to
  30.     // call the iscsi library from normal csharp code
  31.     public class DLLwrap {
  32.         // First we have some constants used throughout the code.
  33.         // These constants are translated from iscsidsc.h
  34.        
  35.         // #define MAX_ISCSI_PORTAL_NAME_LEN 256
  36.         public const ushort MAX_ISCSI_PORTAL_NAME_LEN = 256;
  37.         // #define MAX_ISCSI_PORTAL_ADDRESS_LEN 256
  38.         public const ushort MAX_ISCSI_PORTAL_ADDRESS_LEN = 256;
  39.         // #define MAX_ISCSI_NAME_LEN 223
  40.         public const ushort MAX_ISCSI_NAME_LEN = 223;
  41.         // #define MAX_ISCSI_HBANAME_LEN 256
  42.         public const ushort MAX_ISCSI_HBANAME_LEN = 256;
  43.         // #define ISCSI_ALL_INITIATOR_PORTS ((ULONG)-1)
  44.         public const UInt32 ISCSI_ALL_INITIATOR_PORTS = 4294967295;
  45.         // #define ISCSI_ANY_INITIATOR_PORT ((ULONG)-1)
  46.         public const UInt32 ISCSI_ANY_INITIATOR_PORT = 4294967295;
  47.        
  48.         // Below contant is the size of the ISCSI_TARGET_PORTAL_INFO
  49.         // structure which means that it is equal to:
  50.         //  MAX_ISCSI_HBANAME_LEN +
  51.         //  Size of UInt32 = 4 +
  52.         //  MAX_ISCSI_PORTAL_NAME_LEN +
  53.         //  MAX_ISCSI_PORTAL_ADDRESS_LEN +
  54.         //  Size of ushort = 2 +
  55.         //  (dont know why) 2
  56.         // I do not know why the last two bytes are there making the
  57.         // size 776 bytes instead of 774 bytes, but I found that the
  58.         // structure returned is actually 776 bytes long ????
  59.         public const int ISCSI_TARGET_PORTAL_INFO_SIZE = 776;
  60.        
  61.         // According to MS SDK the MAX_PATH constant is defined as
  62.         // 260 bytes allthough it is possible to work with longer
  63.         // paths in which case MAX_PATH is 32767 bytes.
  64.         // I am guessing that we are only using the short version
  65.         // when working with the iSCSI initiator
  66.         public const int MAX_PATH = 264;
  67.        
  68.         // Below constants are here to ensure that we use the same
  69.         // data type in csharp as is used in c++. It is possible
  70.         // that a normal csharp bool would work just as well.
  71.         public const byte TRUE = 1;
  72.         public const byte FALSE = 0;
  73.        
  74.         // Next we have some structures used by the functions in
  75.         // iscsidsc.dll I have tried to convert them from c++ to
  76.         // csharp as best I could. All information about the
  77.         // structures have also been taken from iscsidsc.h
  78.        
  79.         // typedef struct
  80.         // {
  81.         //  ULONG MajorVersion;
  82.         //  ULONG MinorVersion;
  83.         //  ULONG BuildNumber;
  84.         // } ISCSI_VERSION_INFO, *PISCSI_VERSION_INFO;
  85.         [StructLayout(LayoutKind.Sequential)]
  86.         public struct ISCSI_VERSION_INFO {
  87.             public UInt32 MajorVersion;
  88.             public UInt32 MinorVersion;
  89.             public UInt32 BuildNumber;
  90.         }
  91.        
  92.     // Notice that the name of the struct in c++ is not the
  93.     // same as the name I have used in csharp. This is
  94.     // because the c++ headerfile also has type definitions
  95.     // for unicode ??? I have used the "normal" definitions
  96.         // typedef struct
  97.         // {
  98.         //  CHAR SymbolicName[MAX_ISCSI_PORTAL_NAME_LEN];
  99.         //  CHAR Address[MAX_ISCSI_PORTAL_ADDRESS_LEN];
  100.         //  USHORT Socket;
  101.         // } ISCSI_TARGET_PORTALA, *PISCSI_TARGET_PORTALA;
  102.         [StructLayout(LayoutKind.Sequential)]
  103.         public struct ISCSI_TARGET_PORTAL {
  104.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_NAME_LEN)]
  105.             public byte[] SymbolicName;
  106.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_ADDRESS_LEN)]
  107.             public byte[] Address;
  108.             public ushort Socket;
  109.         }
  110.        
  111.  
  112.     // Each iscsi session and connection has a unique session or connection
  113.     // id that is used to reference the session. It it not related to the
  114.     // actual ISID
  115.         // typedef struct _ISCSI_UNIQUE_SESSION_ID
  116.         // {  
  117.         //  ULONGLONG AdapterUnique;
  118.         //  ULONGLONG AdapterSpecific;
  119.         // } ISCSI_UNIQUE_SESSION_ID, *PISCSI_UNIQUE_SESSION_ID,
  120.         //   ISCSI_UNIQUE_CONNECTION_ID, *PISCSI_UNIQUE_CONNECTION_ID;
  121.         [StructLayout(LayoutKind.Sequential)]
  122.         public struct ISCSI_UNIQUE_SESSION_ID {
  123.             public UInt64 AdapterUnique;
  124.             public UInt64 AdapterSpecific;
  125.         }
  126.        
  127.         [StructLayout(LayoutKind.Sequential)]
  128.         public struct ISCSI_UNIQUE_CONNECTION_ID {
  129.             public UInt64 AdapterUnique;
  130.             public UInt64 AdapterSpecific;
  131.         }
  132.  
  133.         // typedef struct
  134.         // {
  135.         //  CHAR InitiatorName[MAX_ISCSI_HBANAME_LEN];
  136.         //  ULONG InitiatorPortNumber;
  137.         //  CHAR SymbolicName[MAX_ISCSI_PORTAL_NAME_LEN];
  138.         //  CHAR Address[MAX_ISCSI_PORTAL_ADDRESS_LEN];
  139.         //  USHORT Socket;
  140.         // } ISCSI_TARGET_PORTAL_INFOA, *PISCSI_TARGET_PORTAL_INFOA;
  141.         [StructLayout(LayoutKind.Sequential)]
  142.         public struct ISCSI_TARGET_PORTAL_INFO {
  143.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_HBANAME_LEN)]
  144.             public byte[] InitiatorName;
  145.             public UInt32  InitiatorPortNumber;
  146.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_NAME_LEN)]
  147.             public byte[] SymbolicName;
  148.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_PORTAL_ADDRESS_LEN)]
  149.             public byte[] Address;
  150.             public ushort Socket;
  151.         }
  152.        
  153.         // typedef struct
  154.         // {
  155.         //  ULONG OSLUN;
  156.         //  ULONGLONG TargetLUN;
  157.         // } SCSI_LUN_LIST, *PISCSI_LUN_LIST;
  158.         [StructLayout(LayoutKind.Sequential)]
  159.         public struct SCSI_LUN_LIST {
  160.             public UInt32 OSLUN;
  161.             public UInt64 TargetLUN;
  162.         }
  163.        
  164.         // typedef struct
  165.         // {
  166.         //  CHAR InitiatorName[MAX_ISCSI_HBANAME_LEN];
  167.         //  CHAR TargetName[MAX_ISCSI_NAME_LEN + 1];
  168.         // CHAR OSDeviceName[MAX_PATH]; /* \device\ScsiPort3 */
  169.         // ISCSI_UNIQUE_SESSION_ID SessionId;
  170.         // ULONG OSBusNumber;
  171.         // ULONG OSTargetNumber;
  172.         // ULONG LUNCount;
  173.         // #ifdef MIDL_PASS
  174.         //  [size_is(LUNCount)]
  175.         // #endif
  176.         //  PSCSI_LUN_LIST LUNList;
  177.         // } ISCSI_TARGET_MAPPINGA, *PISCSI_TARGET_MAPPINGA;
  178.         [StructLayout(LayoutKind.Sequential)]
  179.         public struct ISCSI_TARGET_MAPPING {
  180.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_HBANAME_LEN)]
  181.             public byte[]                   InitiatorName;
  182.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_ISCSI_NAME_LEN+1)]
  183.             public byte[]                   TargetName;
  184.             [MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_PATH)]
  185.             public byte[]                   OSDeviceName;
  186.             public ISCSI_UNIQUE_SESSION_ID  SessionId;
  187.             public Int32                    OSBusNumber;
  188.             public Int32                    OSTargetNumber;
  189.             public Int32                    LUNCount;
  190.             public IntPtr                   LUNList;
  191.         }
  192.  
  193.  
  194.         // Last we have the actual functions referenced directly from
  195.         // the iscsidsc.dll file. Again I have tried to create the
  196.         // functions as close to the c++ definition as possible
  197.        
  198.        
  199.         // ISDSC_STATUS ISDSC_API GetIScsiInitiatorNodeNameA(
  200.         //  __out_ecount(MAX_ISCSI_NAME_LEN+1) PCHAR  InitiatorNodeName
  201.         // );
  202.         [DllImport("iscsidsc.dll")]
  203.         public static extern uint
  204.             GetIScsiInitiatorNodeName(byte[] NodeName);
  205.  
  206.         // ISDSC_STATUS ISDSC_API GetIScsiVersionInformation(
  207.         //  PISCSI_VERSION_INFO VersionInfo
  208.         // );
  209.         [DllImport("iscsidsc.dll")]
  210.         public static extern uint
  211.             GetIScsiVersionInformation(ref ISCSI_VERSION_INFO VersionInfo);
  212.        
  213.         // ISDSC_STATUS ISDSC_API AddIScsiSendTargetPortalA(
  214.         //  IN OPTIONAL __in_opt PCHAR InitiatorInstance,
  215.         //  IN OPTIONAL ULONG InitiatorPortNumber,
  216.         //  IN OPTIONAL PISCSI_LOGIN_OPTIONS LoginOptions,
  217.         //  IN OPTIONAL ISCSI_SECURITY_FLAGS SecurityFlags,
  218.         //  IN PISCSI_TARGET_PORTALA Portal
  219.         // );
  220.         [DllImport("iscsidsc.dll")]
  221.         public static extern uint
  222.             AddIScsiSendTargetPortal(byte[]                  InitiatorName,
  223.                                      UInt32                  InitiatorPortNumber,
  224.                                      byte[]                  LoginOptions,
  225.                                      UInt64                  SecurityFlags,
  226.                                      ref ISCSI_TARGET_PORTAL Portal);
  227.        
  228.         // ISDSC_STATUS ISDSC_API RemoveIScsiSendTargetPortalA(
  229.         //  IN OPTIONAL PCHAR __in_opt InitiatorInstance,
  230.         //  IN OPTIONAL ULONG InitiatorPortNumber,
  231.         //  IN PISCSI_TARGET_PORTALA Portal
  232.         // );
  233.         [DllImport("iscsidsc.dll")]
  234.         public static extern uint
  235.             RemoveIScsiSendTargetPortal(byte[]                  InitiatorInstance,
  236.                                         UInt32                  InitiatorPortNumber,
  237.                                         ref ISCSI_TARGET_PORTAL Portal);
  238.        
  239.         // ISDSC_STATUS ISDSC_API ReportIScsiSendTargetPortalsA(
  240.         //  IN OUT PULONG PortalCount,
  241.         //  IN OUT PISCSI_TARGET_PORTAL_INFOA PortalInfo
  242.         // );
  243.         [DllImport("iscsidsc.dll")]
  244.         public static extern uint
  245.             ReportIScsiSendTargetPortals(ref UInt32 PortalCount,
  246.                                          //ref ISCSI_TARGET_PORTAL_INFO PortalInfo);
  247.                                          byte[]     PortalInfo);
  248.        
  249.         // ISDSC_STATUS ISDSC_API ReportIScsiTargetsA(
  250.         //  IN BOOLEAN ForceUpdate,
  251.         //  IN OUT PULONG BufferSize,
  252.         //  OUT __inout_ecount_opt(*BufferSize) PCHAR Buffer
  253.         // );
  254.         [DllImport("iscsidsc.dll")]
  255.         public static extern uint
  256.             ReportIScsiTargets(byte       ForceUpdate,
  257.                                ref UInt32 BufferSize,
  258.                                byte[]     Buffer);
  259.        
  260.         // ISDSC_STATUS ISDSC_API LoginIScsiTargetA(
  261.         //  IN PCHAR __in TargetName,
  262.         //  IN BOOLEAN IsInformationalSession,
  263.         //  IN OPTIONAL __in_opt PCHAR InitiatorInstance,
  264.         //  IN OPTIONAL ULONG InitiatorPortNumber,
  265.         //  IN OPTIONAL PISCSI_TARGET_PORTALA TargetPortal,
  266.         //  IN OPTIONAL ISCSI_SECURITY_FLAGS SecurityFlags,
  267.         //  IN OPTIONAL PISCSI_TARGET_MAPPINGA Mappings,
  268.         //  IN OPTIONAL PISCSI_LOGIN_OPTIONS LoginOptions,
  269.         //  IN OPTIONAL ULONG KeySize,
  270.         //  IN OPTIONAL __in_ecount_opt(KeySize) PCHAR Key,
  271.         //  IN BOOLEAN IsPersistent,
  272.         //  OUT PISCSI_UNIQUE_SESSION_ID UniqueSessionId,
  273.         //  OUT PISCSI_UNIQUE_CONNECTION_ID UniqueConnectionId
  274.         // );
  275.         [DllImport("iscsidsc.dll")]
  276.         public static extern uint
  277.             LoginIScsiTarget(byte[]                         TargetName,
  278.                              byte                           IsInformationalSession,
  279.                              byte[]                         InitiatorInstance,
  280.                              UInt32                         InitiatorPortNumber,
  281.                              byte[]                         TargetPortal,
  282.                              UInt64                         SecurityFlags,
  283.                              byte[]                         Mappings,
  284.                              byte[]                         LoginOptions,
  285.                              UInt32                         KeySize,
  286.                              byte[]                         Key,
  287.                              byte                           IsPersistent,
  288.                              ref ISCSI_UNIQUE_SESSION_ID    UniqueSessionId,
  289.                              ref ISCSI_UNIQUE_CONNECTION_ID UniqueConnectionId);
  290.        
  291.         // ISDSC_STATUS ISDSC_API LogoutIScsiTarget(
  292.         //  IN PISCSI_UNIQUE_SESSION_ID UniqueSessionId
  293.         // );
  294.         [DllImport("iscsidsc.dll")]
  295.         public static extern uint
  296.             LogoutIScsiTarget(ref ISCSI_UNIQUE_SESSION_ID UniqueSessionId);
  297.        
  298.         // ISDSC_STATUS ISDSC_API ReportActiveIScsiTargetMappingsA(
  299.         //  IN OUT PULONG BufferSize,
  300.         //  OUT PULONG MappingCount,
  301.         //  OUT PISCSI_TARGET_MAPPINGA Mappings
  302.         // );
  303.         [DllImport("iscsidsc.dll")]
  304.         public static extern uint
  305.             ReportActiveIScsiTargetMappings(ref UInt32 BufferSize,
  306.                                             ref UInt32 MappingCount,
  307.                                             byte[]     Mappings);
  308.     }
  309.  
  310.    
  311.     public class Funcs {
  312.         // This function will check if the iscsidsc.dll (iSCSI initiator) is
  313.         // found in the system.
  314.         // It returns true if the file is found and false if not
  315.         public static bool InitiatorExists() {
  316.             return (
  317.                 System.IO.File.Exists(
  318.                     System.Environment.GetEnvironmentVariable("windir")+
  319.                     "\\system32\\iscsidsc.dll"));
  320.         }
  321.        
  322.         // This function will check if the iSCSI Initiator service is started.
  323.         // If it is not started the function will try to start it.
  324.         // The function returns true if the iSCSI Initiator service is started.
  325.         public static bool InitiatorStarted(int SecondsToWait) {
  326.             // Check if the iSCSI service is running
  327.             try {
  328.                 ServiceController sc = new ServiceController();
  329.                 sc.ServiceName = "MSiSCSI";
  330.                 // the iSCSI server is running we are good to go.
  331.                 if (sc.Status == ServiceControllerStatus.Running)
  332.                     return (true);
  333.                 else {
  334.                     // If the iSCSI service is not running, try to start it
  335.                     try {
  336.                         sc.Start();
  337.                         // Wait SecondsToWait for the service to start
  338.                         sc.WaitForStatus(ServiceControllerStatus.Running,
  339.                                          TimeSpan.FromSeconds((double)SecondsToWait));
  340.                     // If the service could not start, we return false
  341.                     } catch {
  342.                         return (false);
  343.                     }
  344.                 }
  345.             // If the service was not found, we return false  
  346.             } catch {
  347.                 return (false);
  348.             }
  349.            
  350.             // If we reach this point the service exists and is started.
  351.             return (true);
  352.         }
  353.        
  354.         // This function retrieves the iSCSI Initiator Node Name
  355.         // from the iSCSI initiator and returns it in a string
  356.         public static string GetInitiatorNodeName() {
  357.             // Create a buffer that can contain a maximum of
  358.             // MAX_ISCSI_NAME_LEN+1 bytes
  359.             byte[] NodeName = new byte[DLLwrap.MAX_ISCSI_NAME_LEN+1];
  360.             uint Status;
  361.            
  362.             // If the call to GetIScsiInititatorNodeName returns a
  363.             // value of 0 (zero), it has succeeded and the variable
  364.             // NodeName should contain the name of the Initiator
  365.             if ((Status=DLLwrap.GetIScsiInitiatorNodeName(NodeName))==0) {
  366.                 // The GetString function is not designed to work with
  367.                 // 0 (null) terminated strings so we need to tell it
  368.                 // how many bytes to copy. This is done by finding the
  369.                 // first occurence of a 0 (zero).
  370.                 int strlen = Array.IndexOf(NodeName, (byte)0);
  371.                 // Return the Initiator name as a string
  372.                 return (System.Text.Encoding.ASCII.GetString(NodeName, (byte)0, strlen)+"\n");
  373.             } else
  374.                 return (GetErrDef(Status)+"\n");
  375.         }
  376.        
  377.         // This function retrieves the iSCSI Initiator version
  378.         // from the iSCSI initiator and returns it in a string
  379.         public static string GetVersionInformation() {
  380.             DLLwrap.ISCSI_VERSION_INFO VersionInfo =
  381.                 new DLLwrap.ISCSI_VERSION_INFO();
  382.             uint Status;
  383.            
  384.             // If the call to GetIScsiVersionInformation returns a
  385.             // value of 0 (zero), it has succeeded and the variable
  386.             // VersionInfo should contain the version of the Initiator
  387.             if ((Status=DLLwrap.GetIScsiVersionInformation(ref VersionInfo))==0)
  388.                 // Build a string out of the version information and
  389.                 // return it.
  390.                 return(VersionInfo.MajorVersion.ToString()+"."+
  391.                        VersionInfo.MinorVersion.ToString()+"."+
  392.                        VersionInfo.BuildNumber.ToString()+"\n");
  393.             else
  394.                 return(GetErrDef(Status)+"\n");
  395.         }
  396.        
  397.         // This function tries to add a SendTarget Portal to the
  398.         // Initiator. It takes two inputs, Portal and Socket.
  399.         // Portal: A string containing the address of the iSCSI
  400.         //         target, normally a FQDN or IP address
  401.         // Socket: The port on the iSCSI target that should be
  402.         //         connected to, normally 3260
  403.         public static string AddSendTargetPortal(string Portal, ushort Socket) {
  404.             int cnt; // cnt (counter) is used to copy the Portal string
  405.             uint Status;
  406.             // Create a new instance of the ISCSI_TARGET_PORTAL structure
  407.             DLLwrap.ISCSI_TARGET_PORTAL TargetPortal =
  408.                 new DLLwrap.ISCSI_TARGET_PORTAL();
  409.            
  410.             // Allocate memory for the contained Address
  411.             TargetPortal.Address =
  412.                 new byte[DLLwrap.MAX_ISCSI_PORTAL_ADDRESS_LEN];
  413.             // Allocate memory for the contained Name
  414.             // allthough it is not used we need to allocate the memory
  415.             // to ensure that the socket value will be in the correct
  416.             // place in memory
  417.             TargetPortal.SymbolicName =
  418.                 new byte[DLLwrap.MAX_ISCSI_PORTAL_NAME_LEN];
  419.            
  420.             // Add the socket value to the TargetPortal structure
  421.             TargetPortal.Socket = Socket;
  422.            
  423.             // Copy the address in Portal to the Address variable of
  424.             // the TargetPortal structure. It is done in this way to
  425.             // ensure that the allocated memory of the Address
  426.             // variable remains the same.
  427.             for (cnt=0; cnt<Portal.Length; cnt++)
  428.                 TargetPortal.Address[cnt] = (byte)Portal[cnt];
  429.             TargetPortal.Address[cnt] = (byte)0; // Ensure string is 0 terminated
  430.            
  431.             // If the call to AddIScsiSendTargetPortal returns 0 (zero) it
  432.             // has succeeded and the Target Portal should have been added.
  433.             // According the the MS SDK documentation the only input that this
  434.             // function needs is the pointer to ISCSI_TARGET_PORTAL, the others
  435.             // are optional. This means that we can use default values.
  436.             // InitiatorName = null
  437.             // InitiatorPortNumber = ISCSI_ALL_INITIATOR_PORTS
  438.             // LoginOptions = null
  439.             // SecurityFlags = 0
  440.             if ((Status=DLLwrap.AddIScsiSendTargetPortal(null,
  441.                                                       DLLwrap.ISCSI_ALL_INITIATOR_PORTS,
  442.                                                       null,
  443.                                                       0,
  444.                                                       ref TargetPortal))==0)
  445.                 return ("Added portal "+Portal+"\n");
  446.             else
  447.                 return (GetErrDef(Status)+"\n");
  448.         }
  449.        
  450.         // This function tries to remove a SendTarget Portal from the
  451.         // Initiator. It takes two inputs, Portal and Socket.
  452.         // Portal: A string containing the address of the iSCSI
  453.         //         target, normally a FQDN or IP address
  454.         // Socket: The port on the iSCSI target that was
  455.         //         connected to, normally 3260    
  456.         public static string RemoveSendTargetPortal(string Portal, ushort Socket) {
  457.             int cnt; // cnt (counter) is used to copy the Portal string
  458.             uint Status;
  459.            
  460.             // Create a new instance of the ISCSI_TARGET_PORTAL structure
  461.             DLLwrap.ISCSI_TARGET_PORTAL TargetPortal =
  462.                 new DLLwrap.ISCSI_TARGET_PORTAL();
  463.            
  464.             // Allocate memory for the contained Address
  465.             TargetPortal.Address =
  466.                 new byte[DLLwrap.MAX_ISCSI_PORTAL_ADDRESS_LEN];
  467.             // Allocate memory for the contained Name
  468.             // allthough it is not used we need to allocate the memory
  469.             // to ensure that the socket value will be in the correct
  470.             // place in memory
  471.             TargetPortal.SymbolicName =
  472.                 new byte[DLLwrap.MAX_ISCSI_PORTAL_NAME_LEN];
  473.            
  474.             // Add the socket value to the TargetPortal structure
  475.             TargetPortal.Socket = Socket;
  476.            
  477.             // Copy the address in Portal to the Address variable of
  478.             // the TargetPortal structure. It is done in this way to
  479.             // ensure that the allocated memory of the Address
  480.             // variable remains the same.
  481.             for (cnt=0; cnt<Portal.Length; cnt++)
  482.                 TargetPortal.Address[cnt] = (byte)Portal[cnt];
  483.             TargetPortal.Address[cnt] = (byte)0; // Ensure string is 0 terminated
  484.            
  485.             // If the call to RemoveIScsiSendTargetPortal returns 0 (zero) it
  486.             // has succeeded and the Target Portal should have been added.
  487.             // According the the MS SDK documentation the only input that this
  488.             // function needs is the pointer to ISCSI_TARGET_PORTAL, the others
  489.             // are optional. This means that we can use default values.
  490.             // InitiatorInstance = null
  491.             // InitiatorPortNumber = ISCSI_ALL_INITIATOR_PORTS
  492.             if ((Status=DLLwrap.RemoveIScsiSendTargetPortal(null,
  493.                                                          DLLwrap.ISCSI_ALL_INITIATOR_PORTS,
  494.                                                          ref TargetPortal))==0)
  495.                 return ("Removed portal "+Portal+"\n");
  496.             else
  497.                 return (GetErrDef(Status)+"\n");
  498.         }
  499.        
  500.         // This function will copy data from a byte array to a structure of
  501.         // ISCSI_TARGET_PORTAL_INFO.
  502.         // It takes two inputs, a byte array and a starting point in the buffer
  503.         // Buff: byte[] that is allready allocated and filled in
  504.         // Start: the address in the byte array where the structure should start
  505.         // The function returns a filled in ISCSI_TARGET_PORTAL_INFO structure
  506.         // This function has not been made public in the class as the only place
  507.         // it is used so far is within the class.
  508.         static DLLwrap.ISCSI_TARGET_PORTAL_INFO BuffToPortalInfo(byte[] Buff, int Start) {
  509.             return (
  510.                 (DLLwrap.ISCSI_TARGET_PORTAL_INFO)Marshal.PtrToStructure(
  511.                     Marshal.UnsafeAddrOfPinnedArrayElement(Buff,
  512.                                                            DLLwrap.ISCSI_TARGET_PORTAL_INFO_SIZE*Start),
  513.                 typeof(DLLwrap.ISCSI_TARGET_PORTAL_INFO)));
  514.             // To be honest, I am not exactly sure how or why above code works,
  515.             // but it does.
  516.         }      
  517.  
  518.         // This function tells which Target Portals are allready
  519.         // added to the iSCSI initiator
  520.         public static string ReportSendTargetPortals() {
  521.             string str="";
  522.             uint NumPortals=0, cnt;
  523.             byte[] PortalInfoBuffer;
  524.             DLLwrap.ISCSI_TARGET_PORTAL_INFO PortalInfo;
  525.            
  526.             // Do an initial call to find out how many portals are allready
  527.             // registered in the iSCSI initiator
  528.             DLLwrap.ReportIScsiSendTargetPortals(ref NumPortals, null);
  529.             // If there are more than 0 portals, retrive the list.
  530.             if (NumPortals > 0) {
  531.                 // Allocate memory to hold the list of portals.
  532.                 PortalInfoBuffer = new byte[NumPortals*DLLwrap.ISCSI_TARGET_PORTAL_INFO_SIZE];
  533.                 str = NumPortals.ToString()+" portal(s) found\n";
  534.                
  535.                 // Get the list of portals from the iSCSI initiator.
  536.                 // The function returns them as an array of
  537.                 // ISCSI_TARGET_PORTAL_INFO structures
  538.                 // I have not been able to make Csharp work correctly with an
  539.                 // array of structures so a byte buffer is used.
  540.                 DLLwrap.ReportIScsiSendTargetPortals(ref NumPortals, PortalInfoBuffer);
  541.                
  542.                 // For each portal in the list
  543.                 for (cnt=0; cnt<NumPortals; cnt++) {
  544.                     // Convert the byte array to a useable structure
  545.                     PortalInfo = BuffToPortalInfo(PortalInfoBuffer, (int)cnt);
  546.                     // Add the portal address and socket to the returned string
  547.                     str += System.Text.Encoding.ASCII.GetString(
  548.                         PortalInfo.Address,
  549.                         0,
  550.                         Array.IndexOf(PortalInfo.Address, (byte)0));
  551.                     str += ", "+PortalInfo.Socket.ToString()+"\n";
  552.                 }
  553.             } else str = "No portals found\n";
  554.            
  555.             return (str);
  556.         }
  557.        
  558.         // This function reports all targets that the iSCSI initiator
  559.         // has access to. This means that targets from all portals are shown
  560.         public static string ReportTargets() {
  561.             string str="";
  562.             uint BufferSize=0, BuffCnt=0;
  563.             int strlen;
  564.             byte[] Buff;
  565.            
  566.             // Do an initial call to the function to find the buffersize
  567.             DLLwrap.ReportIScsiTargets(DLLwrap.TRUE, ref BufferSize, null);
  568.            
  569.             // If BufferSize is larger than 0 it means that we have targets
  570.             if (BufferSize > 0) {
  571.                 // Allocate memory for that list of targets
  572.                 Buff = new byte[BufferSize];
  573.                
  574.                 // If the call to ReportIScsiTargets returns a status of 0 it has
  575.                 // succeeded and we can get the targets from the buffer
  576.                 if (DLLwrap.ReportIScsiTargets(DLLwrap.TRUE, ref BufferSize, Buff)==0) {
  577.                     // The buffer contains a series of 0 terminated strings ending with
  578.                     // an extra 0 termination so we should cycle through the buffer
  579.                     // untill we hit a 0
  580.                     while (Buff[BuffCnt] != (byte)0) {
  581.                         // Calculate the length of the first string
  582.                         strlen = Array.IndexOf(Buff, (byte)0, (int)BuffCnt)-(int)BuffCnt;
  583.                
  584.                         str += System.Text.Encoding.ASCII.GetString(
  585.                             Buff, (int)BuffCnt, strlen)+"\n";
  586.                        
  587.                         // Count through the buffer until we find the next 0 termination
  588.                         while (Buff[BuffCnt++] != (byte)0);
  589.                     }
  590.                     // For some reason it seems that the ReportIScsiTargets function
  591.                     // wants us to allocate a few bytes in the buffer even though
  592.                     // there are no targets so below we check the string that is to
  593.                     // be returned. If it does not contain anything it means that
  594.                     // there were no targets.
  595.                     if (str=="") str = "No targets found\n";
  596.                 } else str = "Error - Could not get targets in to buffer\n";
  597.             } else str = "No targets found\n";
  598.            
  599.             return (str);
  600.         }
  601.        
  602.         // This function will try to log in to the target specified by
  603.         // TargetName. If it is successfull it will return a string
  604.         // containing the word Success, the target name, the
  605.         // specific adapter session ID and the unique adapter session id
  606.         public static string LoginTarget(string TargetName) {
  607.             string str="";
  608.             uint Status;
  609.            
  610.             DLLwrap.ISCSI_UNIQUE_SESSION_ID SessionID =
  611.                 new DLLwrap.ISCSI_UNIQUE_SESSION_ID();
  612.             DLLwrap.ISCSI_UNIQUE_CONNECTION_ID ConnectionID =
  613.                 new DLLwrap.ISCSI_UNIQUE_CONNECTION_ID();
  614.            
  615.             // The LoginIScsiTarget function takes a total of 14 inputs
  616.             // where 11 of those are optional. The only ones that must
  617.             // be specified are TargetName, SessionID and ConnectionID.
  618.             // If the function returns 0 (zero) it has successfully
  619.             // logged in to the specified target.
  620.             if ((Status=DLLwrap.LoginIScsiTarget(
  621.                     System.Text.Encoding.ASCII.GetBytes(TargetName),
  622.                     DLLwrap.FALSE,null,DLLwrap.ISCSI_ANY_INITIATOR_PORT,
  623.                     null,0,null,null,0,null,DLLwrap.FALSE,
  624.                     ref SessionID,
  625.                     ref ConnectionID))==0) {
  626.                 // Create the string that is returned on success
  627.                 str += TargetName+",";
  628.                 str += SessionID.AdapterUnique.ToString()+",";
  629.                 str += SessionID.AdapterSpecific.ToString()+"\n";
  630.             } else str = "Error - Unable to log in to target: "+TargetName+" - "+GetErrDef(Status)+"\n";
  631.             return (str);
  632.         }
  633.        
  634.         // This function will log out of a specified iSCSI target.
  635.         // TargetName should contain the name of the target that should be logged out.
  636.         public static string LogoutTarget(string TargetName) {
  637.             string str="";
  638.             string Mappings;
  639.             string[] StrArr;
  640.             DLLwrap.ISCSI_UNIQUE_SESSION_ID SessionID = new DLLwrap.ISCSI_UNIQUE_SESSION_ID();
  641.            
  642.             // Get the active mappings
  643.             Mappings = ReportActiveTargetMappings();
  644.            
  645.             // If above function has returned a string containing "Error" or
  646.             // "No mappings" we can not continue.
  647.             if (Mappings.Contains("Error") || Mappings.Contains("No mappings"))
  648.                 str = "Error - No mapping to "+TargetName+" found\n";
  649.             else {
  650.                 // If the TargetName specified is found in the mappings, we can
  651.                 // log out of it. Otherwise return an error
  652.                 if (Mappings.Contains(TargetName)) {
  653.                     // Split the string in to lines containing a single target
  654.                     StrArr = Mappings.Split('\n');
  655.                    
  656.                     // For each target
  657.                     foreach (string tmpstr in StrArr) {
  658.                         // If we have found the TargetName that we want
  659.                         if (tmpstr.Contains(TargetName)) {
  660.                             // Split the string at ',' to get TargetName and
  661.                             // SessionID in individual strings.
  662.                             StrArr = tmpstr.Split(',');
  663.                            
  664.                             // Convert the strings to ISCSI_UNIQUE_SESSION_ID structure
  665.                             SessionID.AdapterUnique = System.Convert.ToUInt64(StrArr[1]);
  666.                             SessionID.AdapterSpecific = System.Convert.ToUInt64(StrArr[2]);
  667.                            
  668.                             // Do the actual log out of the target
  669.                             // If LogoutIScsiTarget return 0 (zero) the target has
  670.                             // successfully been logged out.
  671.                             if (DLLwrap.LogoutIScsiTarget(ref SessionID)==0)
  672.                                 str = "Success - Logged out of "+TargetName+"\n";
  673.                             else
  674.                                 str = "Error - Unable to log out of "+TargetName+"\n";
  675.                         }
  676.                     }
  677.                 } else str = "Error - No mapping to "+TargetName+" found\n";
  678.             }
  679.             return (str);
  680.         }
  681.        
  682.         // This function will copy data from a byte array to a structure of
  683.         // ISCSI_TARGET_MAPPING.
  684.         // It takes two inputs, a byte array and a starting point in the buffer
  685.         // Buff: byte[] that is allready allocated and filled in
  686.         // Start: the address in the byte array where the structure should start
  687.         // The function returns a filled in ISCSI_TARGET_MAPPING structure
  688.         // This function has not been made public in the class as the only place
  689.         // it is used so far is within the class.
  690.         static DLLwrap.ISCSI_TARGET_MAPPING BuffToTargetMapping(byte[] Buff, int Start) {
  691.             return (
  692.                 (DLLwrap.ISCSI_TARGET_MAPPING)Marshal.PtrToStructure(
  693.                     Marshal.UnsafeAddrOfPinnedArrayElement(Buff,
  694.                                                            Start),
  695.                     typeof(DLLwrap.ISCSI_TARGET_MAPPING)));
  696.             // To be honest, I am not exactly sure how or why above code works,
  697.             // but it does.
  698.         }      
  699.  
  700.         // This function will return a list of active targets from the iSCSI
  701.         // initiator. Returning a list of connected targets with their
  702.         // respective SessionID's.
  703.         public static string ReportActiveTargetMappings() {
  704.             string str="";
  705.             byte[] TargetMapBuffer;
  706.             DLLwrap.ISCSI_TARGET_MAPPING TargetMapping;
  707.             uint BufferSize=0, MappingCount=0;
  708.             int mapcnt;
  709.            
  710.             // Define the size of the ISCSI_TARGET_MAPPING structure
  711.             int TargetMapSize = DLLwrap.MAX_ISCSI_HBANAME_LEN+
  712.                                 DLLwrap.MAX_ISCSI_NAME_LEN+1+
  713.                                 DLLwrap.MAX_PATH+
  714.                                 16+ // Size of ISCSI_UNIQUE_SESSION_ID
  715.                                 (sizeof(UInt32)*3)+ // OSBusNumber, OSTargetNumber & LUNCount
  716.                                 sizeof(UInt32); // Size of SCSI_LUN_LIST pointer
  717.            
  718.             // Do an initial call to ReportActiveIScsiTargetMappings to find the
  719.             // buffer size
  720.             DLLwrap.ReportActiveIScsiTargetMappings(ref BufferSize, ref MappingCount, null);
  721.            
  722.             // If BufferSize is larger than 0, we are connected to targets.
  723.             if (BufferSize > 0) {
  724.                 // Allocate memory for the bufferr
  725.                 TargetMapBuffer = new byte[BufferSize];
  726.                
  727.                 // If the call to ReportActiveIScsiTargetMappings returns
  728.                 // 0 (zero) it has succeeded and the buffer is filled with
  729.                 // ISCSI_TARGET_MAPPING structures.
  730.                 if (DLLwrap.ReportActiveIScsiTargetMappings(ref BufferSize,
  731.                                                             ref MappingCount,
  732.                                                             TargetMapBuffer)==0) {
  733.                     // For each mapping the data from the buffer is copied to an
  734.                     // ISCSI_TARGET_MAPPING structure
  735.                     for (mapcnt=1; mapcnt<=MappingCount; mapcnt++) {
  736.                         TargetMapping = BuffToTargetMapping(TargetMapBuffer,
  737.                                                             (mapcnt-1)*TargetMapSize);
  738.                        
  739.                         // Copy the target name to the string beeing returned
  740.                         str += System.Text.Encoding.ASCII.GetString(
  741.                             TargetMapping.TargetName,
  742.                             0,
  743.                             Array.IndexOf(TargetMapping.TargetName, (byte)0))+",";
  744.                        
  745.                         // Copy the session ID to the string beeing returned.
  746.                         str += TargetMapping.SessionId.AdapterUnique.ToString()+",";
  747.                         str += TargetMapping.SessionId.AdapterSpecific.ToString()+"\n";
  748.                     }
  749.                 } else str = "Error - Unable to get target mappings in buffer\n";  
  750.             } else str = "No mappings found\n";
  751.             return (str);
  752.         }
  753.        
  754.         // This function will return a string corresponding to the
  755.         // Status code, as defined in winerror.h
  756.         // As not all error codes has been implemented it will
  757.         // return a general error string with the Status code if
  758.         // it is unable to return the correct error definition.
  759.         // All error codes are copied from:
  760.         // http://msdn.microsoft.com/en-us/library/ms819773.aspx
  761.         static string GetErrDef(uint Status) {
  762.             switch (Status) {
  763.                     case  0: return ("NO_ERROR");
  764.                     case  1: return ("ERROR_INVALID_FUNCTION");
  765.                     case  2: return ("ERROR_FILE_NOT_FOUND");
  766.                     case  3: return ("ERROR_PATH_NOT_FOUND");
  767.                     case  4: return ("ERROR_TOO_MANY_OPEN_FILES");
  768.                     case  5: return ("ERROR_ACCESS_DENIED");
  769.                     case  6: return ("ERROR_INVALID_HANDLE");
  770.                     case  7: return ("ERROR_ARENA_TRASHED");
  771.                     case  8: return ("ERROR_NOT_ENOUGH_MEMORY");
  772.                     case  9: return ("ERROR_INVALID_BLOCK");
  773.                     case 10: return ("ERROR_BAD_ENVIRONMENT");
  774.                     case 11: return ("ERROR_BAD_FORMAT");
  775.                     case 12: return ("ERROR_INVALID_ACCESS");
  776.                     case 13: return ("ERROR_INVALID_DATA");
  777.                     case 14: return ("ERROR_OUTOFMEMORY");
  778.                     case 15: return ("ERROR_INVALID_DRIVE");
  779.                     case 16: return ("ERROR_CURRENT_DIRECTORY");
  780.                     case 17: return ("ERROR_NOT_SAME_DEVICE");
  781.                     case 18: return ("ERROR_NO_MORE_FILES");
  782.                     case 19: return ("ERROR_WRITE_PROTECT");
  783.                     case 20: return ("ERROR_BAD_UNIT");
  784.                     case 21: return ("ERROR_NOT_READY");
  785.                     case 22: return ("ERROR_BAD_COMMAND");
  786.                     case 23: return ("ERROR_CRC");
  787.                     case 24: return ("ERROR_BAD_LENGTH");
  788.                     case 25: return ("ERROR_SEEK");
  789.                     case 26: return ("ERROR_NOT_DOS_DISK");
  790.                     case 27: return ("ERROR_SECTOR_NOT_FOUND");
  791.                     case 28: return ("ERROR_OUT_OF_PAPER");
  792.                     case 29: return ("ERROR_READ_FAULT");
  793.                     case 30: return ("ERROR_READ_FAULT");
  794.                     default: return ("UNKNOWN - "+Status.ToString());
  795.             }
  796.         }
  797.  
  798.     }
  799. }

PasteIT is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.