aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs')
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/UniAddress.cs591
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();
+ }
+ }
+}