Iscsi.cs

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

Raw Paste

Comments 0
Login to post a comment.
  • No comments yet. Be the first.
Login to post a comment. Login or Register
We use cookies. To comply with GDPR in the EU and the UK we have to show you these.

We use cookies and similar technologies to keep this website functional (including spam protection via Google reCAPTCHA), and — with your consent — to measure usage and show ads. See Privacy.