/* Copyright (C) 2016 Tal Aloni . All rights reserved. * * You can redistribute this program and/or modify it under the terms of * the GNU Lesser Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. */ using ISCSI.Server; using ISCSIConsole.Mods; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Windows.Forms; using DiskAccessLibrary; using SCSI; using Utilities; namespace ISCSIConsole { public partial class MainForm : BaseForm { private ISCSIServer m_server = new ISCSIServer(); private List m_targets = new List(); private UsageCounter m_usageCounter = new UsageCounter(); private bool m_started = false; public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; Text += " v" + version.ToString(3); m_server.OnLogEntry += Program.OnLogEntry; var localIPs = GetHostIPAddresses(); var list = new KeyValuePairList(); list.Add("Any", IPAddress.Any); foreach (var address in localIPs) { list.Add(address.ToString(), address); } comboIPAddress.DataSource = list; comboIPAddress.DisplayMember = "Key"; comboIPAddress.ValueMember = "Value"; lblStatus.Text = "Author: Tal Aloni (tal.aloni.il@gmail.com)"; #if Win32 if (!SecurityHelper.IsAdministrator()) { lblStatus.Text = "Some features require administrator privileges and have been disabled"; } #endif } private void btnStart_Click(object sender, EventArgs e) { if (!m_started) { var serverAddress = (IPAddress)comboIPAddress.SelectedValue; var port = Conversion.ToInt32(txtPort.Text, 0); if (port <= 0 || port > UInt16.MaxValue) { MessageBox.Show("Invalid TCP port", "Error"); return; } var endpoint = new IPEndPoint(serverAddress, port); try { m_server.Start(endpoint); } catch (SocketException ex) { MessageBox.Show("Cannot start server, " + ex.Message, "Error"); return; } btnStart.Text = "Stop"; txtPort.Enabled = false; comboIPAddress.Enabled = false; m_started = true; UpdateUI(); } else { m_server.Stop(); lblStatus.Text = String.Empty; m_started = false; btnStart.Text = "Start"; txtPort.Enabled = true; comboIPAddress.Enabled = true; } } private void btnAddTarget_Click(object sender, EventArgs e) { var addTarget = new AddTargetForm(); var addTargetResult = addTarget.ShowDialog(); if (addTargetResult == DialogResult.OK) { var target = addTarget.Target; try { AddTarget(target); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error"); } } } private void AddTarget(ISCSITarget target) { ((SCSI.VirtualSCSITarget)target.SCSITarget).OnLogEntry += Program.OnLogEntry; target.OnAuthorizationRequest += ISCSITarget_OnAuthorizationRequest; target.OnSessionTermination += ISCSITarget_OnSessionTermination; m_targets.Add(target); m_server.AddTarget(target); listTargets.Items.Add(target.TargetName); } private void btnRemoveTarget_Click(object sender, EventArgs e) { if (listTargets.SelectedIndices.Count > 0) { var targetIndex = listTargets.SelectedIndices[0]; var target = m_targets[targetIndex]; var isTargetRemoved = m_server.RemoveTarget(target.TargetName); if (!isTargetRemoved) { MessageBox.Show("Could not remove iSCSI target", "Error"); return; } var disks = ((SCSI.VirtualSCSITarget)target.SCSITarget).Disks; LockUtils.ReleaseDisks(disks); m_targets.RemoveAt(targetIndex); listTargets.Items.RemoveAt(targetIndex); } } private void ISCSITarget_OnAuthorizationRequest(object sender, AuthorizationRequestArgs e) { var targetName = ((ISCSITarget)sender).TargetName; m_usageCounter.NotifySessionStart(targetName); UpdateUI(); } private void ISCSITarget_OnSessionTermination(object sender, SessionTerminationArgs e) { var targetName = ((ISCSITarget)sender).TargetName; m_usageCounter.NotifySessionTermination(targetName); UpdateUI(); } private void UpdateUI() { if (InvokeRequired) { Invoke((MethodInvoker)UpdateUI); } else { if (m_started) { lblStatus.Text = String.Format("{0} Active Sessions", m_usageCounter.SessionCount); } if (listTargets.SelectedIndices.Count > 0) { var targetIndex = listTargets.SelectedIndices[0]; var target = m_targets[targetIndex]; var isInUse = m_usageCounter.IsTargetInUse(target.TargetName); btnRemoveTarget.Enabled = !isInUse; } else { btnRemoveTarget.Enabled = false; } } } private static List GetHostIPAddresses() { var result = new List(); foreach (var netInterface in NetworkInterface.GetAllNetworkInterfaces()) { var ipProperties = netInterface.GetIPProperties(); foreach (var addressInfo in ipProperties.UnicastAddresses) { if (addressInfo.Address.AddressFamily == AddressFamily.InterNetwork) { result.Add(addressInfo.Address); } } } return result; } private void listTargets_SelectedIndexChanged(object sender, EventArgs e) { UpdateUI(); } private void LoadConfigButton_Click(object sender, EventArgs e) { LoadFromConfig(); } private void LoadFromConfig() { var entries = ((List)ConfigurationManager.GetSection("autoLoad")).Where(p => p.Enable).ToArray(); if (entries.Length != entries.Select(p => p.Iqn).Distinct().Count()) { MessageBox.Show("Config error: Iqn should no duplicate"); return; } foreach (var entry in entries) { if (m_targets.Any(p => p.TargetName == entry.Iqn)) continue; AddTarget(entry.CreateTarget()); } } private void MainForm_Shown(object sender, EventArgs e) { if (IPAddress.TryParse(ConfigurationManager.AppSettings["Listen"], out var ipAddress)) comboIPAddress.Text = ipAddress.ToString(); if (int.TryParse(ConfigurationManager.AppSettings["Port"], out var port)) txtPort.Text = port.ToString(); if ("true" == ConfigurationManager.AppSettings["AutoLoadConfig"]) LoadFromConfig(); if ("true" == ConfigurationManager.AppSettings["AutoStart"]) btnStart_Click(null, null); } private void listTargets_DoubleClick(object sender, EventArgs e) { if (listTargets.SelectedIndices.Count == 0) return; var targetIndex = listTargets.SelectedIndices[0]; var target = m_targets[targetIndex]; if (target.Target is VirtualSCSITarget v) { if (v.Disks.Count == 0) { MainContextMenuStrip.Items.Add("(no Disks)").Enabled = false; } else { var dic = new Dictionary(); foreach (var disk in v.Disks) { switch (disk) { case BlockDifferencingDiskImage bdd: if (false == bdd.IsNoBaseImage) { var toolStripMenuItem = new ToolStripMenuItem("Clean"); toolStripMenuItem.Click += (o, args) => { var dr = MessageBox.Show($"Are you sure to clean `{bdd.Path}'", "Clean snapshot", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (dr == DialogResult.Yes) bdd.Clean(); }; dic[bdd.Path] = new ToolStripItem[] { toolStripMenuItem }; } break; } } if (dic.Count == 0) MainContextMenuStrip.Items.Add("(no option able Disks)").Enabled = false; else { foreach (var item in dic) { var m = new ToolStripMenuItem(item.Key); m.DropDownItems.AddRange(item.Value); MainContextMenuStrip.Items.Add(m); } } } MainContextMenuStrip.Show(MousePosition); } else { MainContextMenuStrip.Items.Add("(non Virtual SCSI Target)").Enabled = false; MainContextMenuStrip.Show(MousePosition); } } private void MainContextMenuStrip_Closed(object sender, ToolStripDropDownClosedEventArgs e) { MainContextMenuStrip.Items.Clear(); } } }