diff options
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs')
| -rw-r--r-- | Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs b/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs new file mode 100644 index 000000000..816fbe781 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs @@ -0,0 +1,591 @@ +// 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.IO; +using System.Linq; +using System.Net; +using SharpCifs.Netbios; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; +using Extensions = SharpCifs.Util.Sharpen.Extensions; + +namespace SharpCifs +{ + /// <summary> + /// <p>Under normal conditions it is not necessary to use + /// this class to use jCIFS properly. + /// </summary> + /// <remarks> + /// <p>Under normal conditions it is not necessary to use + /// this class to use jCIFS properly. Name resolusion is + /// handled internally to the <code>jcifs.smb</code> package. + /// <p> + /// This class is a wrapper for both + /// <see cref="Jcifs.Netbios.NbtAddress">Jcifs.Netbios.NbtAddress</see> + /// and + /// <see cref="System.Net.IPAddress">System.Net.IPAddress</see> + /// . The name resolution mechanisms + /// used will systematically query all available configured resolution + /// services including WINS, broadcasts, DNS, and LMHOSTS. See + /// <a href="../../resolver.html">Setting Name Resolution Properties</a> + /// and the <code>jcifs.resolveOrder</code> property. Changing + /// jCIFS name resolution properties can greatly affect the behavior of + /// the client and may be necessary for proper operation. + /// <p> + /// This class should be used in favor of <tt>InetAddress</tt> to resolve + /// hostnames on LANs and WANs that support a mixture of NetBIOS/WINS and + /// DNS resolvable hosts. + /// </remarks> + public class UniAddress + { + private const int ResolverWins = 0; + + private const int ResolverBcast = 1; + + private const int ResolverDns = 2; + + private const int ResolverLmhosts = 3; + + private static int[] _resolveOrder; + + private static IPAddress _baddr; + + private static LogStream _log = LogStream.GetInstance(); + + static UniAddress() + { + string ro = Config.GetProperty("jcifs.resolveOrder"); + IPAddress nbns = NbtAddress.GetWinsAddress(); + try + { + _baddr = Config.GetInetAddress("jcifs.netbios.baddr", Extensions.GetAddressByName + ("255.255.255.255")); + } + catch (UnknownHostException) + { + } + if (string.IsNullOrEmpty(ro)) + { + if (nbns == null) + { + _resolveOrder = new int[3]; + _resolveOrder[0] = ResolverLmhosts; + _resolveOrder[1] = ResolverDns; + _resolveOrder[2] = ResolverBcast; + } + else + { + _resolveOrder = new int[4]; + _resolveOrder[0] = ResolverLmhosts; + _resolveOrder[1] = ResolverWins; + _resolveOrder[2] = ResolverDns; + _resolveOrder[3] = ResolverBcast; + } + } + else + { + int[] tmp = new int[4]; + StringTokenizer st = new StringTokenizer(ro, ","); + int i = 0; + while (st.HasMoreTokens()) + { + string s = st.NextToken().Trim(); + if (Runtime.EqualsIgnoreCase(s, "LMHOSTS")) + { + tmp[i++] = ResolverLmhosts; + } + else + { + if (Runtime.EqualsIgnoreCase(s, "WINS")) + { + if (nbns == null) + { + if (_log.Level > 1) + { + _log.WriteLine("UniAddress resolveOrder specifies WINS however the " + "jcifs.netbios.wins property has not been set" + ); + } + continue; + } + tmp[i++] = ResolverWins; + } + else + { + if (Runtime.EqualsIgnoreCase(s, "BCAST")) + { + tmp[i++] = ResolverBcast; + } + else + { + if (Runtime.EqualsIgnoreCase(s, "DNS")) + { + tmp[i++] = ResolverDns; + } + else + { + if (_log.Level > 1) + { + _log.WriteLine("unknown resolver method: " + s); + } + } + } + } + } + } + _resolveOrder = new int[i]; + Array.Copy(tmp, 0, _resolveOrder, 0, i); + } + } + + internal class Sem + { + internal Sem(int count) + { + this.Count = count; + } + + internal int Count; + } + + internal class QueryThread : Thread + { + internal Sem Sem; + + internal string Host; + + internal string Scope; + + internal int Type; + + internal NbtAddress[] Ans; + + internal IPAddress Svr; + + internal UnknownHostException Uhe; + + internal QueryThread(Sem sem, string host, int type, string scope, IPAddress + svr) : base("JCIFS-QueryThread: " + host) + { + this.Sem = sem; + this.Host = host; + this.Type = type; + this.Scope = scope; + this.Svr = svr; + } + + public override void Run() + { + try + { + //Ans = new [] { NbtAddress.GetByName(Host, Type, Scope, Svr) }; + Ans = NbtAddress.GetAllByName(Host, Type, Scope, Svr); + } + catch (UnknownHostException uhe) + { + this.Uhe = uhe; + } + catch (Exception ex) + { + Uhe = new UnknownHostException(ex.Message); + } + finally + { + lock (Sem) + { + Sem.Count--; + Runtime.Notify(Sem); + } + } + } + } + + /// <exception cref="UnknownHostException"></exception> + internal static NbtAddress[] LookupServerOrWorkgroup(string name, IPAddress svr) + { + Sem sem = new Sem(2); + int type = NbtAddress.IsWins(svr) ? unchecked(0x1b) : unchecked(0x1d); + QueryThread q1X = new QueryThread(sem, name, type, null, svr + ); + QueryThread q20 = new QueryThread(sem, name, unchecked(0x20), null, svr); + q1X.SetDaemon(true); + q20.SetDaemon(true); + try + { + lock (sem) + { + q1X.Start(); + q20.Start(); + while (sem.Count > 0 && q1X.Ans == null && q20.Ans == null) + { + Runtime.Wait(sem); + } + } + } + catch (Exception) + { + throw new UnknownHostException(name); + } + if (q1X.Ans != null) + { + return q1X.Ans; + } + if (q20.Ans != null) + { + return q20.Ans; + } + throw q1X.Uhe; + } + + /// <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 + /// machine name like "jcifs.samba.org", or an IP address like "192.168.1.15". + /// </remarks> + /// <param name="hostname">NetBIOS or DNS hostname to resolve</param> + /// <exception cref="UnknownHostException">if there is an error resolving the name + /// </exception> + public static UniAddress GetByName(string hostname) + { + return GetByName(hostname, false); + } + + internal static bool IsDotQuadIp(string hostname) + { + if (char.IsDigit(hostname[0])) + { + int i; + int len; + int dots; + char[] data; + i = dots = 0; + len = hostname.Length; + data = hostname.ToCharArray(); + while (i < len && char.IsDigit(data[i++])) + { + if (i == len && dots == 3) + { + // probably an IP address + return true; + } + if (i < len && data[i] == '.') + { + dots++; + i++; + } + } + } + return false; + } + + internal static bool IsAllDigits(string hostname) + { + for (int i = 0; i < hostname.Length; i++) + { + if (char.IsDigit(hostname[i]) == false) + { + return false; + } + } + return true; + } + + /// <summary>Lookup <tt>hostname</tt> and return it's <tt>UniAddress</tt>.</summary> + /// <remarks> + /// Lookup <tt>hostname</tt> and return it's <tt>UniAddress</tt>. If the + /// <tt>possibleNTDomainOrWorkgroup</tt> parameter is <tt>true</tt> an + /// addtional name query will be performed to locate a master browser. + /// </remarks> + /// <exception cref="UnknownHostException"></exception> + public static UniAddress GetByName(string hostname, bool possibleNtDomainOrWorkgroup + ) + { + UniAddress[] addrs = GetAllByName(hostname, possibleNtDomainOrWorkgroup + ); + return addrs[0]; + } + + /// <exception cref="UnknownHostException"></exception> + public static UniAddress[] GetAllByName(string hostname, bool possibleNtDomainOrWorkgroup + ) + { + object addr; + int i; + if (string.IsNullOrEmpty(hostname)) + { + throw new UnknownHostException(); + } + if (IsDotQuadIp(hostname)) + { + UniAddress[] addrs = new UniAddress[1]; + addrs[0] = new UniAddress(NbtAddress.GetByName(hostname)); + return addrs; + } + for (i = 0; i < _resolveOrder.Length; i++) + { + try + { + switch (_resolveOrder[i]) + { + case ResolverLmhosts: + { + if ((addr = Lmhosts.GetByName(hostname)) == null) + { + continue; + } + break; + } + + case ResolverWins: + { + if (hostname == NbtAddress.MasterBrowserName || hostname.Length > 15) + { + // invalid netbios name + continue; + } + if (possibleNtDomainOrWorkgroup) + { + addr = LookupServerOrWorkgroup(hostname, NbtAddress.GetWinsAddress()); + } + else + { + addr = NbtAddress.GetByName(hostname, unchecked(0x20), null, NbtAddress.GetWinsAddress + ()); + } + break; + } + + case ResolverBcast: + { + if (hostname.Length > 15) + { + // invalid netbios name + continue; + } + + try + { + if (possibleNtDomainOrWorkgroup) + { + NbtAddress[] iaddrs = LookupServerOrWorkgroup(hostname, _baddr); + + UniAddress[] addrs = new UniAddress[iaddrs.Length]; + for (int ii = 0; ii < iaddrs.Length; ii++) + { + addrs[ii] = new UniAddress(iaddrs[ii]); + } + return addrs; + + } + else + { + addr = NbtAddress.GetByName(hostname, unchecked(0x20), null, _baddr); + } + + } + catch (Exception ex) + { + if (i == _resolveOrder.Length - 1) + { + throw ex; + } + else + { + continue; + } + } + break; + } + + case ResolverDns: + { + if (IsAllDigits(hostname)) + { + throw new UnknownHostException(hostname); + } + + IPAddress[] iaddrs = Extensions.GetAddressesByName(hostname); + + if (iaddrs == null || iaddrs.Length == 0) + { + continue; + } + + return iaddrs.Select(iaddr => new UniAddress(iaddr)).ToArray(); + } + + default: + { + // Success + throw new UnknownHostException(hostname); + } + } + UniAddress[] addrs1 = new UniAddress[1]; + addrs1[0] = new UniAddress(addr); + return addrs1; + } + catch (IOException) + { + } + } + // Success + // Failure + throw new UnknownHostException(hostname); + } + + internal object Addr; + + internal string CalledName; + + /// <summary> + /// Create a <tt>UniAddress</tt> by wrapping an <tt>InetAddress</tt> or + /// <tt>NbtAddress</tt>. + /// </summary> + /// <remarks> + /// Create a <tt>UniAddress</tt> by wrapping an <tt>InetAddress</tt> or + /// <tt>NbtAddress</tt>. + /// </remarks> + public UniAddress(object addr) + { + if (addr == null) + { + throw new ArgumentException(); + } + this.Addr = addr; + } + + /// <summary>Return the IP address of this address as a 32 bit integer.</summary> + /// <remarks>Return the IP address of this address as a 32 bit integer.</remarks> + public override int GetHashCode() + { + return Addr.GetHashCode(); + } + + /// <summary>Compare two addresses for equality.</summary> + /// <remarks> + /// Compare two addresses for equality. Two <tt>UniAddress</tt>s are equal + /// if they are both <tt>UniAddress</tt>' and refer to the same IP address. + /// </remarks> + public override bool Equals(object obj) + { + return obj is UniAddress && Addr.Equals(((UniAddress)obj).Addr); + } + + /// <summary>Guess first called name to try for session establishment.</summary> + /// <remarks> + /// Guess first called name to try for session establishment. This + /// method is used exclusively by the <tt>jcifs.smb</tt> package. + /// </remarks> + public virtual string FirstCalledName() + { + if (Addr is NbtAddress) + { + return ((NbtAddress)Addr).FirstCalledName(); + } + CalledName = ((IPAddress) Addr).GetHostAddress(); + if (IsDotQuadIp(CalledName)) + { + CalledName = NbtAddress.SmbserverName; + } + else + { + int i = CalledName.IndexOf('.'); + if (i > 1 && i < 15) + { + CalledName = Runtime.Substring(CalledName, 0, i).ToUpper(); + } + else + { + if (CalledName.Length > 15) + { + CalledName = NbtAddress.SmbserverName; + } + else + { + CalledName = CalledName.ToUpper(); + } + } + } + return CalledName; + } + + /// <summary>Guess next called name to try for session establishment.</summary> + /// <remarks> + /// Guess next called name to try for session establishment. This + /// method is used exclusively by the <tt>jcifs.smb</tt> package. + /// </remarks> + public virtual string NextCalledName() + { + if (Addr is NbtAddress) + { + return ((NbtAddress)Addr).NextCalledName(); + } + if (CalledName != NbtAddress.SmbserverName) + { + CalledName = NbtAddress.SmbserverName; + return CalledName; + } + return null; + } + + /// <summary>Return the underlying <tt>NbtAddress</tt> or <tt>InetAddress</tt>.</summary> + /// <remarks>Return the underlying <tt>NbtAddress</tt> or <tt>InetAddress</tt>.</remarks> + public virtual object GetAddress() + { + return Addr; + } + + /// <summary>Return the hostname of this address such as "MYCOMPUTER".</summary> + /// <remarks>Return the hostname of this address such as "MYCOMPUTER".</remarks> + public virtual string GetHostName() + { + if (Addr is NbtAddress) + { + return ((NbtAddress)Addr).GetHostName(); + } + return ((IPAddress) Addr).GetHostAddress(); + } + + /// <summary>Return the IP address as text such as "192.168.1.15".</summary> + /// <remarks>Return the IP address as text such as "192.168.1.15".</remarks> + public virtual string GetHostAddress() + { + if (Addr is NbtAddress) + { + return ((NbtAddress)Addr).GetHostAddress(); + } + return ((IPAddress)Addr).GetHostAddress(); + } + + public virtual IPAddress GetHostIpAddress() + { + return (IPAddress) Addr; + } + + /// <summary> + /// Return the a text representation of this address such as + /// <tt>MYCOMPUTER/192.168.1.15</tt>. + /// </summary> + /// <remarks> + /// Return the a text representation of this address such as + /// <tt>MYCOMPUTER/192.168.1.15</tt>. + /// </remarks> + public override string ToString() + { + return Addr.ToString(); + } + } +} |
