diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Common/IPAddress.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Common/IPAddress.cs index 556d173a..b283060f 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Common/IPAddress.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Common/IPAddress.cs @@ -5,7 +5,7 @@ using System.Web; namespace WebsitePanel.EnterpriseServer { - public struct IPAddress { + public struct IPAddress : IComparable { public Int128 Address; public bool V6 { get; private set; } public bool V4 { get { return !V6 || Null; } } @@ -68,10 +68,19 @@ namespace WebsitePanel.EnterpriseServer { if (Null) return ""; var s = new System.Text.StringBuilder(); - if (!V6) { - var ipl = Address; - s.Append(String.Format("{0}.{1}.{2}.{3}", (ipl >> 24) & 0xFFL, (ipl >> 16) & 0xFFL, (ipl >> 8) & 0xFFL, (ipl & 0xFFL))); - } else if (!IsMask) { + if (!V6) + { + var ipl = Address; + if (IsMask) + { + int digits = 32 - Cidr; + ipl = (Int128.MaxValue << 1) | 0x1; // remove left sign bit + ipl = ipl << digits; + } + s.Append(String.Format("{0}.{1}.{2}.{3}", (ipl >> 24) & 0xFFL, (ipl >> 16) & 0xFFL, (ipl >> 8) & 0xFFL, (ipl & 0xFFL))); + } + else if (!IsMask) + { var vals = new List(); int i; @@ -127,6 +136,30 @@ namespace WebsitePanel.EnterpriseServer { public static bool operator >(IPAddress a, IPAddress b) { return a.Address > b.Address; } public static bool operator <=(IPAddress a, IPAddress b) { return a.Address <= b.Address; } public static bool operator >=(IPAddress a, IPAddress b) { return a.Address >= b.Address; } + + public override bool Equals(object obj) + { + if (obj is IPAddress) + { + var b = (IPAddress)obj; + return this.Address == b.Address && this.Null == b.Null && (this.Null || !(this.IsSubnet && b.IsSubnet || this.IsMask && b.IsMask) || this.Cidr == b.Cidr); + } + else if (obj is long) + { + var b = (long)obj; + return this.Address == b; + } + else + { + return false; + } + } + + public override int GetHashCode() + { + return this.Address.GetHashCode(); + } + /* public static IPAddress operator +(IPAddress a, IPAddress b) { if (a.IsSubnet || b.IsSubnet || a.V6 != b.V6) throw new ArgumentException("Arithmetic with subnets or mixed v4 & v6 addresses not supported."); @@ -157,7 +190,20 @@ namespace WebsitePanel.EnterpriseServer { } public static implicit operator IPAddress(NullIPAddress a) { return new IPAddress { Null = true, Address = 0, Cidr = -1 }; } - } + + public int CompareTo(object obj) + { + var a = this.Address; + var b = ((IPAddress)obj).Address; + + if (a < b) + return 1; + else if (a > b) + return -1; + else + return 0; + } + } public class NullIPAddress { } diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Virtualization/VirtualizationServerController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Virtualization/VirtualizationServerController.cs index 5f8abb8d..e9eb4862 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Virtualization/VirtualizationServerController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/Code/Virtualization/VirtualizationServerController.cs @@ -39,6 +39,7 @@ using WebsitePanel.Providers; using System.Text; using System.Collections; using System.Net.Mail; +using System.Diagnostics; namespace WebsitePanel.EnterpriseServer { @@ -2991,6 +2992,18 @@ namespace WebsitePanel.EnterpriseServer public static ResultObject AddVirtualMachinePrivateIPAddresses(int itemId, bool selectRandom, int addressesNumber, string[] addresses, bool provisionKvp) { + // trace info + Trace.TraceInformation("Entering AddVirtualMachinePrivateIPAddresses()"); + Trace.TraceInformation("Item ID: {0}", itemId); + Trace.TraceInformation("SelectRandom: {0}", selectRandom); + Trace.TraceInformation("AddressesNumber: {0}", addressesNumber); + + if (addresses != null) + { + foreach(var address in addresses) + Trace.TraceInformation("addresses[n]: {0}", address); + } + ResultObject res = new ResultObject(); // load service item @@ -3026,6 +3039,9 @@ namespace WebsitePanel.EnterpriseServer bool wasEmptyList = (nic.IPAddresses.Length == 0); + if(wasEmptyList) + Trace.TraceInformation("NIC IP addresses list is empty"); + // check IP addresses if they are specified List checkResults = CheckPrivateIPAddresses(vm.PackageId, addresses); if (checkResults.Count > 0) @@ -3213,51 +3229,68 @@ namespace WebsitePanel.EnterpriseServer private static string GenerateNextAvailablePrivateIP(SortedList ips, string subnetMask, string startIPAddress) { - // start IP address - var startIp = IPAddress.Parse(startIPAddress); - var mask = IPAddress.Parse(subnetMask); + Trace.TraceInformation("Entering GenerateNextAvailablePrivateIP()"); + Trace.TraceInformation("Param - number of sorted IPs in the list: {0}", ips.Count); + Trace.TraceInformation("Param - startIPAddress: {0}", startIPAddress); + Trace.TraceInformation("Param - subnetMask: {0}", subnetMask); - var lastAddress = (startIp & ~mask) - 1; + // start IP address + var ip = IPAddress.Parse(startIPAddress) - 1; + + Trace.TraceInformation("Start looking for next available IP"); foreach (var addr in ips.Keys) { - if ((addr - lastAddress) > 1) + if ((addr - ip) > 1) { // it is a gap break; } else { - lastAddress = addr; + ip = addr; } } - var genAddr = lastAddress + 1; + // final IP found + ip = ip + 1; - // convert to IP address - var ip = startIp & mask | genAddr; string genIP = ip.ToString(); + Trace.TraceInformation("Generated IP: {0}", genIP); // store in cache - ips.Add(genAddr, genIP); + Trace.TraceInformation("Adding to sorted list"); + ips.Add(ip, genIP); + Trace.TraceInformation("Leaving GenerateNextAvailablePrivateIP()"); return genIP; } private static SortedList GetSortedNormalizedIPAddresses(List ips, string subnetMask) { + Trace.TraceInformation("Entering GetSortedNormalizedIPAddresses()"); + Trace.TraceInformation("Param - subnetMask: {0}", subnetMask); + var mask = IPAddress.Parse(subnetMask); SortedList sortedIps = new SortedList(); foreach (PrivateIPAddress ip in ips) { var addr = ~mask & IPAddress.Parse(ip.IPAddress); sortedIps.Add(addr, ip.IPAddress); + + Trace.TraceInformation("Added {0} to sorted IPs list with key: {1} ", ip.IPAddress, addr.ToString()); } return sortedIps; } private static string GetPrivateNetworkSubnetMask(string cidr, bool v6) { - if (v6) return "/" + cidr; - else return IPAddress.Parse("/" + cidr).ToV4MaskString(); + if (v6) + { + return "/" + cidr; + } + else + { + return IPAddress.Parse("/" + cidr).ToV4MaskString(); + } } private static string GetSubnetMaskCidr(string subnetMask) { diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/App_LocalResources/WebSitesAddSite.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/App_LocalResources/WebSitesAddSite.ascx.resx index f34ebbf3..fd1eabe9 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/App_LocalResources/WebSitesAddSite.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/App_LocalResources/WebSitesAddSite.ascx.resx @@ -142,7 +142,7 @@ If you need your web site to be accessible via dedicated IP address or you are planning to enable SSL for your site you should choose "Dedicated IP" option; otherwise leave this settings by default. In order to create IP-based site you need to purchase IP address from your host. - + Note: A Zone Template is often defined by your host and contains additional Web Site Pointers to create when creating a new Web Site. Static record definitions such as 'www' conflicts when creating an additional Web Site in the same Domain. Dedicated