mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 10:37:22 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			921 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			921 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // This code is derived from jcifs smb client library <jcifs at samba dot org>
 | |
| // Ported by J. Arturo <webmaster at komodosoft dot net>
 | |
| //  
 | |
| // This library is free software; you can redistribute it and/or
 | |
| // modify it under the terms of the GNU Lesser General Public
 | |
| // License as published by the Free Software Foundation; either
 | |
| // version 2.1 of the License, or (at your option) any later version.
 | |
| // 
 | |
| // This library is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| // Lesser General Public License for more details.
 | |
| // 
 | |
| // You should have received a copy of the GNU Lesser General Public
 | |
| // License along with this library; if not, write to the Free Software
 | |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| using System;
 | |
| using System.Linq;
 | |
| using System.Net;
 | |
| using SharpCifs.Util;
 | |
| using SharpCifs.Util.Sharpen;
 | |
| using Extensions = SharpCifs.Util.Sharpen.Extensions;
 | |
| 
 | |
| namespace SharpCifs.Netbios
 | |
| {
 | |
| 	/// <summary>This class represents a NetBIOS over TCP/IP address.</summary>
 | |
| 	/// <remarks>
 | |
| 	/// This class represents a NetBIOS over TCP/IP address. Under normal
 | |
| 	/// conditions, users of jCIFS need not be concerned with this class as
 | |
| 	/// name resolution and session services are handled internally by the smb package.
 | |
| 	/// <p> Applications can use the methods <code>getLocalHost</code>,
 | |
| 	/// <code>getByName</code>, and
 | |
| 	/// <code>getAllByAddress</code> to create a new NbtAddress instance. This
 | |
| 	/// class is symmetric with
 | |
| 	/// <see cref="System.Net.IPAddress">System.Net.IPAddress</see>
 | |
| 	/// .
 | |
| 	/// <p><b>About NetBIOS:</b> The NetBIOS name
 | |
| 	/// service is a dynamic distributed service that allows hosts to resolve
 | |
| 	/// names by broadcasting a query, directing queries to a server such as
 | |
| 	/// Samba or WINS. NetBIOS is currently the primary networking layer for
 | |
| 	/// providing name service, datagram service, and session service to the
 | |
| 	/// Microsoft Windows platform. A NetBIOS name can be 15 characters long
 | |
| 	/// and hosts usually registers several names on the network. From a
 | |
| 	/// Windows command prompt you can see
 | |
| 	/// what names a host registers with the nbtstat command.
 | |
| 	/// <p><blockquote><pre>
 | |
| 	/// C:\>nbtstat -a 192.168.1.15
 | |
| 	/// NetBIOS Remote Machine Name Table
 | |
| 	/// Name               Type         Status
 | |
| 	/// ---------------------------------------------
 | |
| 	/// JMORRIS2        <00>  UNIQUE      Registered
 | |
| 	/// BILLING-NY      <00>  GROUP       Registered
 | |
| 	/// JMORRIS2        <03>  UNIQUE      Registered
 | |
| 	/// JMORRIS2        <20>  UNIQUE      Registered
 | |
| 	/// BILLING-NY      <1E>  GROUP       Registered
 | |
| 	/// JMORRIS         <03>  UNIQUE      Registered
 | |
| 	/// MAC Address = 00-B0-34-21-FA-3B
 | |
| 	/// </blockquote></pre>
 | |
| 	/// <p> The hostname of this machine is <code>JMORRIS2</code>. It is
 | |
| 	/// a member of the group(a.k.a workgroup and domain) <code>BILLING-NY</code>. To
 | |
| 	/// obtain an
 | |
| 	/// <see cref="System.Net.IPAddress">System.Net.IPAddress</see>
 | |
| 	/// for a host one might do:
 | |
| 	/// <pre>
 | |
| 	/// InetAddress addr = NbtAddress.getByName( "jmorris2" ).getInetAddress();
 | |
| 	/// </pre>
 | |
| 	/// <p>From a UNIX platform with Samba installed you can perform similar
 | |
| 	/// diagnostics using the <code>nmblookup</code> utility.
 | |
| 	/// </remarks>
 | |
| 	/// <author>Michael B. Allen</author>
 | |
| 	/// <seealso cref="System.Net.IPAddress">System.Net.IPAddress</seealso>
 | |
| 	/// <since>jcifs-0.1</since>
 | |
| 	public sealed class NbtAddress
 | |
| 	{
 | |
| 		internal static readonly string AnyHostsName = "*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000";
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// This is a special name for querying the master browser that serves the
 | |
| 		/// list of hosts found in "Network Neighborhood".
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// This is a special name for querying the master browser that serves the
 | |
| 		/// list of hosts found in "Network Neighborhood".
 | |
| 		/// </remarks>
 | |
| 		public static readonly string MasterBrowserName = "\u0001\u0002__MSBROWSE__\u0002";
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// A special generic name specified when connecting to a host for which
 | |
| 		/// a name is not known.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// A special generic name specified when connecting to a host for which
 | |
| 		/// a name is not known. Not all servers respond to this name.
 | |
| 		/// </remarks>
 | |
| 		public static readonly string SmbserverName = "*SMBSERVER     ";
 | |
| 
 | |
| 		/// <summary>A B node only broadcasts name queries.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// A B node only broadcasts name queries. This is the default if a
 | |
| 		/// nameserver such as WINS or Samba is not specified.
 | |
| 		/// </remarks>
 | |
| 		public const int BNode = 0;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// A Point-to-Point node, or P node, unicasts queries to a nameserver
 | |
| 		/// only.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// A Point-to-Point node, or P node, unicasts queries to a nameserver
 | |
| 		/// only. Natrually the <code>jcifs.netbios.nameserver</code> property must
 | |
| 		/// be set.
 | |
| 		/// </remarks>
 | |
| 		public const int PNode = 1;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Try Broadcast queries first, then try to resolve the name using the
 | |
| 		/// nameserver.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>
 | |
| 		/// Try Broadcast queries first, then try to resolve the name using the
 | |
| 		/// nameserver.
 | |
| 		/// </remarks>
 | |
| 		public const int MNode = 2;
 | |
| 
 | |
| 		/// <summary>A Hybrid node tries to resolve a name using the nameserver first.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// A Hybrid node tries to resolve a name using the nameserver first. If
 | |
| 		/// that fails use the broadcast address. This is the default if a nameserver
 | |
| 		/// is provided. This is the behavior of Microsoft Windows machines.
 | |
| 		/// </remarks>
 | |
| 		public const int HNode = 3;
 | |
| 
 | |
| 		internal static readonly IPAddress[] Nbns = Config.GetInetAddressArray("jcifs.netbios.wins"
 | |
| 			, ",", new IPAddress[0]);
 | |
| 
 | |
| 		private static readonly NameServiceClient Client = new NameServiceClient();
 | |
| 
 | |
| 		private const int DefaultCachePolicy = 30;
 | |
| 
 | |
| 		private static readonly int CachePolicy = Config.GetInt("jcifs.netbios.cachePolicy"
 | |
| 			, DefaultCachePolicy);
 | |
| 
 | |
| 		private const int Forever = -1;
 | |
| 
 | |
| 		private static int _nbnsIndex;
 | |
| 
 | |
| 		private static readonly Hashtable AddressCache = new Hashtable();
 | |
| 
 | |
| 		private static readonly Hashtable LookupTable = new Hashtable();
 | |
| 
 | |
| 		internal static readonly Name UnknownName = new Name("0.0.0.0", unchecked(0x00), null);
 | |
| 
 | |
| 		internal static readonly NbtAddress UnknownAddress = new NbtAddress
 | |
| 			(UnknownName, 0, false, BNode);
 | |
| 
 | |
| 		internal static readonly byte[] UnknownMacAddress = { unchecked(unchecked(0x00)), unchecked(unchecked(0x00)), unchecked(unchecked(0x00)), unchecked(unchecked(0x00)), unchecked(unchecked(0x00)), unchecked(unchecked(0x00)) };
 | |
| 
 | |
| 		internal sealed class CacheEntry
 | |
| 		{
 | |
| 			internal Name HostName;
 | |
| 
 | |
| 			internal NbtAddress Address;
 | |
| 
 | |
| 			internal long Expiration;
 | |
| 
 | |
| 			internal CacheEntry(Name hostName, NbtAddress address, long expiration)
 | |
| 			{
 | |
| 				this.HostName = hostName;
 | |
| 				this.Address = address;
 | |
| 				this.Expiration = expiration;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		internal static NbtAddress Localhost;
 | |
| 
 | |
| 		static NbtAddress()
 | |
| 		{
 | |
| 			IPAddress localInetAddress;
 | |
| 			string localHostname;
 | |
| 			Name localName;
 | |
| 			AddressCache.Put(UnknownName, new CacheEntry(UnknownName, UnknownAddress
 | |
| 				, Forever));
 | |
| 			localInetAddress = Client.laddr;
 | |
| 			if (localInetAddress == null)
 | |
| 			{
 | |
| 				try
 | |
| 				{
 | |
|                     localInetAddress = Extensions.GetAddressByName("127.0.0.1");
 | |
| 				}
 | |
| 				catch (UnknownHostException)
 | |
| 				{
 | |
| 
 | |
| 				}
 | |
| 			}
 | |
| 			localHostname = Config.GetProperty("jcifs.netbios.hostname", null);
 | |
| 			if (string.IsNullOrEmpty(localHostname))
 | |
| 			{
 | |
| 				byte[] addr = localInetAddress.GetAddressBytes();
 | |
| 				
 | |
|                 /*localHostname = "JCIFS" + (addr[2] & unchecked((int)(0xFF))) + "_" + (addr[3] & unchecked(
 | |
|                     (int)(0xFF))) + "_" + Hexdump.ToHexString((int)(new Random().NextDouble() * (double)unchecked(
 | |
| 					(int)(0xFF))), 2);*/
 | |
| 			    localHostname = "JCIFS_127_0_0_1";
 | |
| 			}
 | |
| 			localName = new Name(localHostname, unchecked(0x00), Config.GetProperty("jcifs.netbios.scope"
 | |
| 				, null));
 | |
| 			Localhost = new NbtAddress(localName, localInetAddress.GetHashCode(), false, BNode
 | |
| 				, false, false, true, false, UnknownMacAddress);
 | |
| 			CacheAddress(localName, Localhost, Forever);
 | |
| 		}
 | |
| 
 | |
| 		internal static void CacheAddress(Name hostName, NbtAddress addr)
 | |
| 		{
 | |
| 			if (CachePolicy == 0)
 | |
| 			{
 | |
| 				return;
 | |
| 			}
 | |
| 			long expiration = -1;
 | |
| 			if (CachePolicy != Forever)
 | |
| 			{
 | |
| 				expiration = Runtime.CurrentTimeMillis() + CachePolicy * 1000;
 | |
| 			}
 | |
| 			CacheAddress(hostName, addr, expiration);
 | |
| 		}
 | |
| 
 | |
| 		internal static void CacheAddress(Name hostName, NbtAddress addr, long expiration
 | |
| 			)
 | |
| 		{
 | |
| 			if (CachePolicy == 0)
 | |
| 			{
 | |
| 				return;
 | |
| 			}
 | |
| 			lock (AddressCache)
 | |
| 			{
 | |
| 				CacheEntry entry = (CacheEntry)AddressCache.Get(hostName);
 | |
| 				if (entry == null)
 | |
| 				{
 | |
| 					entry = new CacheEntry(hostName, addr, expiration);
 | |
| 					AddressCache.Put(hostName, entry);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					entry.Address = addr;
 | |
| 					entry.Expiration = expiration;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		internal static void CacheAddressArray(NbtAddress[] addrs)
 | |
| 		{
 | |
| 			if (CachePolicy == 0)
 | |
| 			{
 | |
| 				return;
 | |
| 			}
 | |
| 			long expiration = -1;
 | |
| 			if (CachePolicy != Forever)
 | |
| 			{
 | |
| 				expiration = Runtime.CurrentTimeMillis() + CachePolicy * 1000;
 | |
| 			}
 | |
| 			lock (AddressCache)
 | |
| 			{
 | |
| 				for (int i = 0; i < addrs.Length; i++)
 | |
| 				{
 | |
| 					CacheEntry entry = (CacheEntry)AddressCache.Get(addrs[i].HostName
 | |
| 						);
 | |
| 					if (entry == null)
 | |
| 					{
 | |
| 						entry = new CacheEntry(addrs[i].HostName, addrs[i], expiration);
 | |
| 						AddressCache.Put(addrs[i].HostName, entry);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						entry.Address = addrs[i];
 | |
| 						entry.Expiration = expiration;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		internal static NbtAddress GetCachedAddress(Name hostName)
 | |
| 		{
 | |
| 			if (CachePolicy == 0)
 | |
| 			{
 | |
| 				return null;
 | |
| 			}
 | |
| 			lock (AddressCache)
 | |
| 			{
 | |
|                 CacheEntry entry = (CacheEntry)AddressCache.Get(hostName);
 | |
| 				if (entry != null && entry.Expiration < Runtime.CurrentTimeMillis() && entry.Expiration
 | |
| 					 >= 0)
 | |
| 				{
 | |
| 					entry = null;
 | |
| 				}
 | |
| 				return entry != null ? entry.Address : null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		internal static NbtAddress DoNameQuery(Name name, IPAddress svr)
 | |
| 		{
 | |
| 			NbtAddress addr;
 | |
| 			if (name.HexCode == unchecked(0x1d) && svr == null)
 | |
| 			{
 | |
| 				svr = Client.Baddr;
 | |
| 			}
 | |
| 			// bit of a hack but saves a lookup
 | |
| 			name.SrcHashCode = svr != null ? svr.GetHashCode() : 0;
 | |
| 			addr = GetCachedAddress(name);
 | |
| 			if (addr == null)
 | |
| 			{
 | |
| 				if ((addr = (NbtAddress)CheckLookupTable(name)) == null)
 | |
| 				{
 | |
| 					try
 | |
| 					{
 | |
| 						addr = Client.GetByName(name, svr);
 | |
| 					}
 | |
| 					catch (UnknownHostException)
 | |
| 					{
 | |
| 						addr = UnknownAddress;
 | |
| 					}
 | |
| 					finally
 | |
| 					{
 | |
| 						CacheAddress(name, addr);
 | |
| 						UpdateLookupTable(name);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			if (addr == UnknownAddress)
 | |
| 			{
 | |
| 				throw new UnknownHostException(name.ToString());
 | |
| 			}
 | |
| 			return addr;
 | |
| 		}
 | |
| 
 | |
| 		private static object CheckLookupTable(Name name)
 | |
| 		{
 | |
| 			object obj;
 | |
| 			lock (LookupTable)
 | |
| 			{
 | |
| 				if (LookupTable.ContainsKey(name) == false)
 | |
| 				{
 | |
| 					LookupTable.Put(name, name);
 | |
| 					return null;
 | |
| 				}
 | |
| 				while (LookupTable.ContainsKey(name))
 | |
| 				{
 | |
| 					try
 | |
| 					{
 | |
| 						Runtime.Wait(LookupTable);
 | |
| 					}
 | |
| 					catch (Exception)
 | |
| 					{
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			obj = GetCachedAddress(name);
 | |
| 			if (obj == null)
 | |
| 			{
 | |
| 				lock (LookupTable)
 | |
| 				{
 | |
| 					LookupTable.Put(name, name);
 | |
| 				}
 | |
| 			}
 | |
| 			return obj;
 | |
| 		}
 | |
| 
 | |
| 		private static void UpdateLookupTable(Name name)
 | |
| 		{
 | |
| 			lock (LookupTable)
 | |
| 			{
 | |
| 				//Sharpen.Collections.Remove(LOOKUP_TABLE, name);
 | |
|                 LookupTable.Remove(name);
 | |
| 				Runtime.NotifyAll(LookupTable);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Retrieves the local host address.</summary>
 | |
| 		/// <remarks>Retrieves the local host address.</remarks>
 | |
| 		/// <exception cref="UnknownHostException">
 | |
| 		/// This is not likely as the IP returned
 | |
| 		/// by <code>InetAddress</code> should be available
 | |
| 		/// </exception>
 | |
| 		public static NbtAddress GetLocalHost()
 | |
| 		{
 | |
| 			return Localhost;
 | |
| 		}
 | |
| 
 | |
| 	    public static NbtAddress[] GetHosts()
 | |
| 	    {
 | |
| 	        return new NameServiceClient().GetHosts();
 | |
| 	    }
 | |
| 
 | |
| 		public static Name GetLocalName()
 | |
| 		{
 | |
| 			return Localhost.HostName;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines the address of a host given it's host name.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Determines the address of a host given it's host name. The name can be a NetBIOS name like
 | |
| 		/// "freto" or an IP address like "192.168.1.15". It cannot be a DNS name;
 | |
| 		/// the analygous
 | |
| 		/// <see cref="SharpCifs.UniAddress">Jcifs.UniAddress</see>
 | |
| 		/// or
 | |
| 		/// <see cref="System.Net.IPAddress">System.Net.IPAddress</see>
 | |
| 		/// <code>getByName</code> methods can be used for that.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="host">hostname to resolve</param>
 | |
| 		/// <exception cref="UnknownHostException">if there is an error resolving the name
 | |
| 		/// 	</exception>
 | |
| 		public static NbtAddress GetByName(string host)
 | |
| 		{
 | |
| 			return GetByName(host, unchecked(0x00), null);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines the address of a host given it's host name.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Determines the address of a host given it's host name. NetBIOS
 | |
| 		/// names also have a <code>type</code>. Types(aka Hex Codes)
 | |
| 		/// are used to distiquish the various services on a host. <a
 | |
| 		/// href="../../../nbtcodes.html">Here</a> is
 | |
| 		/// a fairly complete list of NetBIOS hex codes. Scope is not used but is
 | |
| 		/// still functional in other NetBIOS products and so for completeness it has been
 | |
| 		/// implemented. A <code>scope</code> of <code>null</code> or <code>""</code>
 | |
| 		/// signifies no scope.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="host">the name to resolve</param>
 | |
| 		/// <param name="type">the hex code of the name</param>
 | |
| 		/// <param name="scope">the scope of the name</param>
 | |
| 		/// <exception cref="UnknownHostException">if there is an error resolving the name
 | |
| 		/// 	</exception>
 | |
| 		public static NbtAddress GetByName(string host, int type, string scope)
 | |
| 		{
 | |
| 			return GetByName(host, type, scope, null);
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public static NbtAddress GetByName(string host, int type, string scope, IPAddress
 | |
| 			 svr)
 | |
| 		{
 | |
| 			if (string.IsNullOrEmpty(host))
 | |
| 			{
 | |
| 				return GetLocalHost();
 | |
| 			}
 | |
| 			if (!char.IsDigit(host[0]))
 | |
| 			{
 | |
| 				return DoNameQuery(new Name(host, type, scope), svr);
 | |
| 			}
 | |
| 		    int ip = unchecked(0x00);
 | |
| 		    int hitDots = 0;
 | |
| 		    char[] data = host.ToCharArray();
 | |
| 		    for (int i = 0; i < data.Length; i++)
 | |
| 		    {
 | |
| 		        char c = data[i];
 | |
| 		        if (c < 48 || c > 57)
 | |
| 		        {
 | |
| 		            return DoNameQuery(new Name(host, type, scope), svr);
 | |
| 		        }
 | |
| 		        int b = unchecked(0x00);
 | |
| 		        while (c != '.')
 | |
| 		        {
 | |
| 		            if (c < 48 || c > 57)
 | |
| 		            {
 | |
| 		                return DoNameQuery(new Name(host, type, scope), svr);
 | |
| 		            }
 | |
| 		            b = b * 10 + c - '0';
 | |
| 		            if (++i >= data.Length)
 | |
| 		            {
 | |
| 		                break;
 | |
| 		            }
 | |
| 		            c = data[i];
 | |
| 		        }
 | |
| 		        if (b > unchecked(0xFF))
 | |
| 		        {
 | |
| 		            return DoNameQuery(new Name(host, type, scope), svr);
 | |
| 		        }
 | |
| 		        ip = (ip << 8) + b;
 | |
| 		        hitDots++;
 | |
| 		    }
 | |
| 		    if (hitDots != 4 || host.EndsWith("."))
 | |
| 		    {
 | |
| 		        return DoNameQuery(new Name(host, type, scope), svr);
 | |
| 		    }
 | |
| 		    return new NbtAddress(UnknownName, ip, false, BNode);
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public static NbtAddress[] GetAllByName(string host, int type, string scope, IPAddress
 | |
| 			 svr)
 | |
| 		{
 | |
| 			return Client.GetAllByName(new Name(host, type, scope), svr);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Retrieve all addresses of a host by it's address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Retrieve all addresses of a host by it's address. NetBIOS hosts can
 | |
| 		/// have many names for a given IP address. The name and IP address make the
 | |
| 		/// NetBIOS address. This provides a way to retrieve the other names for a
 | |
| 		/// host with the same IP address.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="host">hostname to lookup all addresses for</param>
 | |
| 		/// <exception cref="UnknownHostException">if there is an error resolving the name
 | |
| 		/// 	</exception>
 | |
| 		public static NbtAddress[] GetAllByAddress(string host)
 | |
| 		{
 | |
| 			return GetAllByAddress(GetByName(host, unchecked(0x00), null));
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Retrieve all addresses of a host by it's address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Retrieve all addresses of a host by it's address. NetBIOS hosts can
 | |
| 		/// have many names for a given IP address. The name and IP address make
 | |
| 		/// the NetBIOS address. This provides a way to retrieve the other names
 | |
| 		/// for a host with the same IP address.  See
 | |
| 		/// <see cref="GetByName(string)">GetByName(string)</see>
 | |
| 		/// for a description of <code>type</code>
 | |
| 		/// and <code>scope</code>.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="host">hostname to lookup all addresses for</param>
 | |
| 		/// <param name="type">the hexcode of the name</param>
 | |
| 		/// <param name="scope">the scope of the name</param>
 | |
| 		/// <exception cref="UnknownHostException">if there is an error resolving the name
 | |
| 		/// 	</exception>
 | |
| 		public static NbtAddress[] GetAllByAddress(string host, int type, string scope)
 | |
| 		{
 | |
| 			return GetAllByAddress(GetByName(host, type, scope));
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Retrieve all addresses of a host by it's address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Retrieve all addresses of a host by it's address. NetBIOS hosts can
 | |
| 		/// have many names for a given IP address. The name and IP address make the
 | |
| 		/// NetBIOS address. This provides a way to retrieve the other names for a
 | |
| 		/// host with the same IP address.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="addr">the address to query</param>
 | |
| 		/// <exception cref="UnknownHostException">if address cannot be resolved</exception>
 | |
| 		public static NbtAddress[] GetAllByAddress(NbtAddress addr)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				NbtAddress[] addrs = Client.GetNodeStatus(addr);
 | |
| 				CacheAddressArray(addrs);
 | |
| 				return addrs;
 | |
| 			}
 | |
| 			catch (UnknownHostException)
 | |
| 			{
 | |
| 				throw new UnknownHostException("no name with type 0x" + Hexdump.ToHexString(addr.
 | |
| 					HostName.HexCode, 2) + (((addr.HostName.Scope == null) || (addr.HostName.Scope.Length
 | |
| 					 == 0)) ? " with no scope" : " with scope " + addr.HostName.Scope) + " for host "
 | |
| 					 + addr.GetHostAddress());
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public static IPAddress GetWinsAddress()
 | |
| 		{
 | |
| 			return Nbns.Length == 0 ? null : Nbns[_nbnsIndex];
 | |
| 		}
 | |
| 
 | |
| 		public static bool IsWins(IPAddress svr)
 | |
| 		{
 | |
| 			for (int i = 0; svr != null && i < Nbns.Length; i++)
 | |
| 			{
 | |
| 				if (svr.GetHashCode() == Nbns[i].GetHashCode())
 | |
| 				{
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		internal static IPAddress SwitchWins()
 | |
| 		{
 | |
| 			_nbnsIndex = (_nbnsIndex + 1) < Nbns.Length ? _nbnsIndex + 1 : 0;
 | |
| 			return Nbns.Length == 0 ? null : Nbns[_nbnsIndex];
 | |
| 		}
 | |
| 
 | |
| 		internal Name HostName;
 | |
| 
 | |
| 		internal int Address;
 | |
| 
 | |
| 		internal int NodeType;
 | |
| 
 | |
| 		internal bool GroupName;
 | |
| 
 | |
| 		internal bool isBeingDeleted;
 | |
| 
 | |
| 		internal bool isInConflict;
 | |
| 
 | |
| 		internal bool isActive;
 | |
| 
 | |
| 		internal bool isPermanent;
 | |
| 
 | |
| 		internal bool IsDataFromNodeStatus;
 | |
| 
 | |
| 		internal byte[] MacAddress;
 | |
| 
 | |
| 		internal string CalledName;
 | |
| 
 | |
| 		internal NbtAddress(Name hostName, int address, bool groupName, int nodeType)
 | |
| 		{
 | |
| 			this.HostName = hostName;
 | |
| 			this.Address = address;
 | |
| 			this.GroupName = groupName;
 | |
| 			this.NodeType = nodeType;
 | |
| 		}
 | |
| 
 | |
| 		internal NbtAddress(Name hostName, int address, bool groupName, int nodeType, bool
 | |
| 			 isBeingDeleted, bool isInConflict, bool isActive, bool isPermanent, byte[] macAddress
 | |
| 			)
 | |
| 		{
 | |
| 			this.HostName = hostName;
 | |
| 			this.Address = address;
 | |
| 			this.GroupName = groupName;
 | |
| 			this.NodeType = nodeType;
 | |
| 			this.isBeingDeleted = isBeingDeleted;
 | |
| 			this.isInConflict = isInConflict;
 | |
| 			this.isActive = isActive;
 | |
| 			this.isPermanent = isPermanent;
 | |
| 			this.MacAddress = macAddress;
 | |
| 			IsDataFromNodeStatus = true;
 | |
| 		}
 | |
| 
 | |
| 		public string FirstCalledName()
 | |
| 		{
 | |
| 			CalledName = HostName.name;
 | |
| 			if (char.IsDigit(CalledName[0]))
 | |
| 			{
 | |
| 				int i;
 | |
| 				int len;
 | |
| 				int dots;
 | |
| 				char[] data;
 | |
| 				i = dots = 0;
 | |
| 				len = CalledName.Length;
 | |
| 				data = CalledName.ToCharArray();
 | |
| 				while (i < len && char.IsDigit(data[i++]))
 | |
| 				{
 | |
| 					if (i == len && dots == 3)
 | |
| 					{
 | |
| 						// probably an IP address
 | |
| 						CalledName = SmbserverName;
 | |
| 						break;
 | |
| 					}
 | |
| 					if (i < len && data[i] == '.')
 | |
| 					{
 | |
| 						dots++;
 | |
| 						i++;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				switch (HostName.HexCode)
 | |
| 				{
 | |
| 					case unchecked(0x1B):
 | |
| 					case unchecked(0x1C):
 | |
| 					case unchecked(0x1D):
 | |
| 					{
 | |
| 						CalledName = SmbserverName;
 | |
| 					    break;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			return CalledName;
 | |
| 		}
 | |
| 
 | |
| 		public string NextCalledName()
 | |
| 		{
 | |
| 			if (CalledName == HostName.name)
 | |
| 			{
 | |
| 				CalledName = SmbserverName;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if (CalledName == SmbserverName)
 | |
| 				{
 | |
| 					NbtAddress[] addrs;
 | |
| 					try
 | |
| 					{
 | |
| 						addrs = Client.GetNodeStatus(this);
 | |
| 						if (HostName.HexCode == unchecked(0x1D))
 | |
| 						{
 | |
| 							for (int i = 0; i < addrs.Length; i++)
 | |
| 							{
 | |
| 								if (addrs[i].HostName.HexCode == unchecked(0x20))
 | |
| 								{
 | |
| 									return addrs[i].HostName.name;
 | |
| 								}
 | |
| 							}
 | |
| 							return null;
 | |
| 						}
 | |
| 					    if (IsDataFromNodeStatus)
 | |
| 					    {
 | |
| 					        CalledName = null;
 | |
| 					        return HostName.name;
 | |
| 					    }
 | |
| 					}
 | |
| 					catch (UnknownHostException)
 | |
| 					{
 | |
| 						CalledName = null;
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					CalledName = null;
 | |
| 				}
 | |
| 			}
 | |
| 			return CalledName;
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		internal void CheckData()
 | |
| 		{
 | |
| 			if (HostName == UnknownName)
 | |
| 			{
 | |
| 				GetAllByAddress(this);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		internal void CheckNodeStatusData()
 | |
| 		{
 | |
| 			if (IsDataFromNodeStatus == false)
 | |
| 			{
 | |
| 				GetAllByAddress(this);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if the address is a group address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Determines if the address is a group address. This is also
 | |
| 		/// known as a workgroup name or group name.
 | |
| 		/// </remarks>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public bool IsGroupAddress()
 | |
| 		{
 | |
| 			CheckData();
 | |
| 			return GroupName;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Checks the node type of this address.</summary>
 | |
| 		/// <remarks>Checks the node type of this address.</remarks>
 | |
| 		/// <returns>
 | |
| 		/// 
 | |
| 		/// <see cref="BNode">B_NODE</see>
 | |
| 		/// ,
 | |
| 		/// <see cref="PNode">P_NODE</see>
 | |
| 		/// ,
 | |
| 		/// <see cref="MNode">M_NODE</see>
 | |
| 		/// ,
 | |
| 		/// <see cref="HNode">H_NODE</see>
 | |
| 		/// </returns>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public int GetNodeType()
 | |
| 		{
 | |
| 			CheckData();
 | |
| 			return NodeType;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if this address in the process of being deleted.</summary>
 | |
| 		/// <remarks>Determines if this address in the process of being deleted.</remarks>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public bool IsBeingDeleted()
 | |
| 		{
 | |
| 			CheckNodeStatusData();
 | |
| 			return isBeingDeleted;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if this address in conflict with another address.</summary>
 | |
| 		/// <remarks>Determines if this address in conflict with another address.</remarks>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public bool IsInConflict()
 | |
| 		{
 | |
| 			CheckNodeStatusData();
 | |
| 			return isInConflict;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if this address is active.</summary>
 | |
| 		/// <remarks>Determines if this address is active.</remarks>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public bool IsActive()
 | |
| 		{
 | |
| 			CheckNodeStatusData();
 | |
| 			return isActive;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if this address is set to be permanent.</summary>
 | |
| 		/// <remarks>Determines if this address is set to be permanent.</remarks>
 | |
| 		/// <exception cref="UnknownHostException">if the host cannot be resolved to find out.
 | |
| 		/// 	</exception>
 | |
| 		public bool IsPermanent()
 | |
| 		{
 | |
| 			CheckNodeStatusData();
 | |
| 			return isPermanent;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Retrieves the MAC address of the remote network interface.</summary>
 | |
| 		/// <remarks>Retrieves the MAC address of the remote network interface. Samba returns all zeros.
 | |
| 		/// 	</remarks>
 | |
| 		/// <returns>the MAC address as an array of six bytes</returns>
 | |
| 		/// <exception cref="UnknownHostException">
 | |
| 		/// if the host cannot be resolved to
 | |
| 		/// determine the MAC address.
 | |
| 		/// </exception>
 | |
| 		public byte[] GetMacAddress()
 | |
| 		{
 | |
| 			CheckNodeStatusData();
 | |
| 			return MacAddress;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>The hostname of this address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// The hostname of this address. If the hostname is null the local machines
 | |
| 		/// IP address is returned.
 | |
| 		/// </remarks>
 | |
| 		/// <returns>the text representation of the hostname associated with this address</returns>
 | |
| 		public string GetHostName()
 | |
| 		{
 | |
| 			if (HostName == UnknownName)
 | |
| 			{
 | |
| 				return GetHostAddress();
 | |
| 			}
 | |
| 			return HostName.name;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Returns the raw IP address of this NbtAddress.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Returns the raw IP address of this NbtAddress. The result is in network
 | |
| 		/// byte order: the highest order byte of the address is in getAddress()[0].
 | |
| 		/// </remarks>
 | |
| 		/// <returns>a four byte array</returns>
 | |
| 		public byte[] GetAddress()
 | |
| 		{
 | |
| 			byte[] addr = new byte[4];
 | |
| 			addr[0] = unchecked((byte)(((int)(((uint)Address) >> 24)) & unchecked(0xFF
 | |
| 				)));
 | |
| 			addr[1] = unchecked((byte)(((int)(((uint)Address) >> 16)) & unchecked(0xFF
 | |
| 				)));
 | |
| 			addr[2] = unchecked((byte)(((int)(((uint)Address) >> 8)) & unchecked(0xFF)
 | |
| 				));
 | |
| 			addr[3] = unchecked((byte)(Address & unchecked(0xFF)));
 | |
| 			return addr;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>To convert this address to an <code>InetAddress</code>.</summary>
 | |
| 		/// <remarks>To convert this address to an <code>InetAddress</code>.</remarks>
 | |
| 		/// <returns>
 | |
| 		/// the
 | |
| 		/// <see cref="System.Net.IPAddress">System.Net.IPAddress</see>
 | |
| 		/// representation of this address.
 | |
| 		/// </returns>
 | |
| 		/// <exception cref="UnknownHostException"></exception>
 | |
| 		public IPAddress GetInetAddress()
 | |
| 		{
 | |
| 			return Extensions.GetAddressByName(GetHostAddress());
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Returns this IP adress as a
 | |
| 		/// <see cref="string">string</see>
 | |
| 		/// in the form "%d.%d.%d.%d".
 | |
| 		/// </summary>
 | |
| 		public string GetHostAddress()
 | |
| 		{
 | |
| 			return (((int)(((uint)Address) >> 24)) & unchecked(0xFF)) + "." + (((int)(
 | |
| 				((uint)Address) >> 16)) & unchecked(0xFF)) + "." + (((int)(((uint)Address
 | |
| 				) >> 8)) & unchecked(0xFF)) + "." + (((int)(((uint)Address) >> 0)) & unchecked(
 | |
| 				0xFF));
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Returned the hex code associated with this name(e.g.</summary>
 | |
| 		/// <remarks>Returned the hex code associated with this name(e.g. 0x20 is for the file service)
 | |
| 		/// 	</remarks>
 | |
| 		public int GetNameType()
 | |
| 		{
 | |
| 			return HostName.HexCode;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Returns a hashcode for this IP address.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Returns a hashcode for this IP address. The hashcode comes from the IP address
 | |
| 		/// and is not generated from the string representation. So because NetBIOS nodes
 | |
| 		/// can have many names, all names associated with an IP will have the same
 | |
| 		/// hashcode.
 | |
| 		/// </remarks>
 | |
| 		public override int GetHashCode()
 | |
| 		{
 | |
| 			return Address;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>Determines if this address is equal two another.</summary>
 | |
| 		/// <remarks>
 | |
| 		/// Determines if this address is equal two another. Only the IP Addresses
 | |
| 		/// are compared. Similar to the
 | |
| 		/// <see cref="GetHashCode()">GetHashCode()</see>
 | |
| 		/// method, the comparison
 | |
| 		/// is based on the integer IP address and not the string representation.
 | |
| 		/// </remarks>
 | |
| 		public override bool Equals(object obj)
 | |
| 		{
 | |
| 			return (obj != null) && (obj is NbtAddress) && (((NbtAddress)obj).Address == Address
 | |
| 				);
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Returns the
 | |
| 		/// <see cref="string">string</see>
 | |
| 		/// representaion of this address.
 | |
| 		/// </summary>
 | |
| 		public override string ToString()
 | |
| 		{
 | |
| 			return HostName + "/" + GetHostAddress();
 | |
| 		}
 | |
| 	}
 | |
| }
 |