- 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 */
- 20using System;
- 21using System.ServiceProcess;
- 22using System.Runtime.InteropServices;
- 23
- 24namespace 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}
Raw Paste