aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/SharpCifs/Netbios
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2017-08-16 02:43:41 -0400
commitbfcd1b520fd79b893e721ba916ae5e1656407d2f (patch)
tree6a05119800484435fb384da25c6390054a27c3c3 /Emby.Server.Implementations/IO/SharpCifs/Netbios
parente3531534b85aeaaa3e4aaf462d5e77ea142dc762 (diff)
merge common implementations and server implementations
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Netbios')
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs202
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs269
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs52
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs68
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs660
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs448
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs920
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs164
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs59
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs140
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs63
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs54
-rw-r--r--Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs156
13 files changed, 3255 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs
new file mode 100644
index 000000000..c94d0a260
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Lmhosts.cs
@@ -0,0 +1,202 @@
+// 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.IO;
+using SharpCifs.Smb;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ public class Lmhosts
+ {
+ private static readonly string Filename = Config.GetProperty("jcifs.netbios.lmhosts"
+ );
+
+ private static readonly Hashtable Tab = new Hashtable();
+
+ private static long _lastModified = 1L;
+
+ private static int _alt;
+
+ private static LogStream _log = LogStream.GetInstance();
+
+ /// <summary>
+ /// This is really just for
+ /// <see cref="SharpCifs.UniAddress">Jcifs.UniAddress</see>
+ /// . It does
+ /// not throw an
+ /// <see cref="UnknownHostException">Sharpen.UnknownHostException</see>
+ /// because this
+ /// is queried frequently and exceptions would be rather costly to
+ /// throw on a regular basis here.
+ /// </summary>
+ public static NbtAddress GetByName(string host)
+ {
+ lock (typeof(Lmhosts))
+ {
+ return GetByName(new Name(host, 0x20, null));
+ }
+ }
+
+ internal static NbtAddress GetByName(Name name)
+ {
+ lock (typeof(Lmhosts))
+ {
+ NbtAddress result = null;
+ try
+ {
+ if (Filename != null)
+ {
+ FilePath f = new FilePath(Filename);
+ long lm;
+ if ((lm = f.LastModified()) > _lastModified)
+ {
+ _lastModified = lm;
+ Tab.Clear();
+ _alt = 0;
+
+ //path -> fileStream
+ //Populate(new FileReader(f));
+ Populate(new FileReader(new FileStream(f, FileMode.Open)));
+ }
+ result = (NbtAddress)Tab[name];
+ }
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ if (_log.Level > 1)
+ {
+ _log.WriteLine("lmhosts file: " + Filename);
+ Runtime.PrintStackTrace(fnfe, _log);
+ }
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 0)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ }
+ return result;
+ }
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal static void Populate(StreamReader r)
+ {
+ string line;
+ BufferedReader br = new BufferedReader((InputStreamReader)r);
+ while ((line = br.ReadLine()) != null)
+ {
+ line = line.ToUpper().Trim();
+ if (line.Length == 0)
+ {
+ }
+ else
+ {
+ if (line[0] == '#')
+ {
+ if (line.StartsWith("#INCLUDE "))
+ {
+ line = Runtime.Substring(line, line.IndexOf('\\'));
+ string url = "smb:" + line.Replace('\\', '/');
+ if (_alt > 0)
+ {
+ try
+ {
+ Populate(new InputStreamReader(new SmbFileInputStream(url)));
+ }
+ catch (IOException ioe)
+ {
+ _log.WriteLine("lmhosts URL: " + url);
+ Runtime.PrintStackTrace(ioe, _log);
+ continue;
+ }
+ _alt--;
+ while ((line = br.ReadLine()) != null)
+ {
+ line = line.ToUpper().Trim();
+ if (line.StartsWith("#END_ALTERNATE"))
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ Populate(new InputStreamReader(new SmbFileInputStream(url)));
+ }
+ }
+ else
+ {
+ if (line.StartsWith("#BEGIN_ALTERNATE"))
+ {
+ _alt++;
+ }
+ else
+ {
+ if (line.StartsWith("#END_ALTERNATE") && _alt > 0)
+ {
+ _alt--;
+ throw new IOException("no lmhosts alternate includes loaded");
+ }
+ }
+ }
+ }
+ else
+ {
+ if (char.IsDigit(line[0]))
+ {
+ char[] data = line.ToCharArray();
+ int ip;
+ int i;
+ int j;
+ Name name;
+ NbtAddress addr;
+ char c;
+ c = '.';
+ ip = i = 0;
+ for (; i < data.Length && c == '.'; i++)
+ {
+ int b = unchecked(0x00);
+ for (; i < data.Length && (c = data[i]) >= 48 && c <= 57; i++)
+ {
+ b = b * 10 + c - '0';
+ }
+ ip = (ip << 8) + b;
+ }
+ while (i < data.Length && char.IsWhiteSpace(data[i]))
+ {
+ i++;
+ }
+ j = i;
+ while (j < data.Length && char.IsWhiteSpace(data[j]) == false)
+ {
+ j++;
+ }
+ name = new Name(Runtime.Substring(line, i, j), unchecked(0x20), null
+ );
+ addr = new NbtAddress(name, ip, false, NbtAddress.BNode, false, false, true, true
+ , NbtAddress.UnknownMacAddress);
+ Tab.Put(name, addr);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs
new file mode 100644
index 000000000..6c37d57a4
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/Name.cs
@@ -0,0 +1,269 @@
+// 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.Text;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ public class Name
+ {
+ private const int TypeOffset = 31;
+
+ private const int ScopeOffset = 33;
+
+ private static readonly string DefaultScope = Config.GetProperty("jcifs.netbios.scope"
+ );
+
+ internal static readonly string OemEncoding = Config.GetProperty("jcifs.encoding"
+ , Runtime.GetProperty("file.encoding"));
+
+ public string name;
+
+ public string Scope;
+
+ public int HexCode;
+
+ internal int SrcHashCode;
+
+ public Name()
+ {
+ }
+
+ public Name(string name, int hexCode, string scope)
+ {
+ if (name.Length > 15)
+ {
+ name = Runtime.Substring(name, 0, 15);
+ }
+ this.name = name.ToUpper();
+ this.HexCode = hexCode;
+ this.Scope = !string.IsNullOrEmpty(scope) ? scope : DefaultScope;
+ SrcHashCode = 0;
+ }
+
+ internal virtual int WriteWireFormat(byte[] dst, int dstIndex)
+ {
+ // write 0x20 in first byte
+ dst[dstIndex] = unchecked(0x20);
+ // write name
+ try
+ {
+ byte[] tmp = Runtime.GetBytesForString(name, OemEncoding
+ );
+ int i;
+ for (i = 0; i < tmp.Length; i++)
+ {
+ dst[dstIndex + (2 * i + 1)] = unchecked((byte)(((tmp[i] & unchecked(0xF0))
+ >> 4) + unchecked(0x41)));
+ dst[dstIndex + (2 * i + 2)] = unchecked((byte)((tmp[i] & unchecked(0x0F))
+ + unchecked(0x41)));
+ }
+ for (; i < 15; i++)
+ {
+ dst[dstIndex + (2 * i + 1)] = unchecked(unchecked(0x43));
+ dst[dstIndex + (2 * i + 2)] = unchecked(unchecked(0x41));
+ }
+ dst[dstIndex + TypeOffset] = unchecked((byte)(((HexCode & unchecked(0xF0)
+ ) >> 4) + unchecked(0x41)));
+ dst[dstIndex + TypeOffset + 1] = unchecked((byte)((HexCode & unchecked(0x0F)) + unchecked(0x41)));
+ }
+ catch (UnsupportedEncodingException)
+ {
+ }
+ return ScopeOffset + WriteScopeWireFormat(dst, dstIndex + ScopeOffset);
+ }
+
+ internal virtual int ReadWireFormat(byte[] src, int srcIndex)
+ {
+ byte[] tmp = new byte[ScopeOffset];
+ int length = 15;
+ for (int i = 0; i < 15; i++)
+ {
+ tmp[i] = unchecked((byte)(((src[srcIndex + (2 * i + 1)] & unchecked(0xFF))
+ - unchecked(0x41)) << 4));
+ tmp[i] |= unchecked((byte)(((src[srcIndex + (2 * i + 2)] & unchecked(0xFF)
+ ) - unchecked(0x41)) & unchecked(0x0F)));
+ if (tmp[i] != unchecked((byte)' '))
+ {
+ length = i + 1;
+ }
+ }
+ try
+ {
+ name = Runtime.GetStringForBytes(tmp, 0, length, OemEncoding
+ );
+ }
+ catch (UnsupportedEncodingException)
+ {
+ }
+ HexCode = ((src[srcIndex + TypeOffset] & unchecked(0xFF)) - unchecked(0x41)) << 4;
+ HexCode |= ((src[srcIndex + TypeOffset + 1] & unchecked(0xFF)) - unchecked(
+ 0x41)) & unchecked(0x0F);
+ return ScopeOffset + ReadScopeWireFormat(src, srcIndex + ScopeOffset);
+ }
+
+ internal int ReadWireFormatDos(byte[] src, int srcIndex)
+ {
+
+ int length = 15;
+ byte[] tmp = new byte[length];
+
+ Array.Copy(src, srcIndex, tmp, 0, length);
+
+ try
+ {
+ name = Runtime.GetStringForBytes(tmp, 0, length).Trim();
+ }
+ catch (Exception ex)
+ {
+
+ }
+
+ HexCode = src[srcIndex + length];
+
+ return length + 1;
+ }
+
+
+ internal virtual int WriteScopeWireFormat(byte[] dst, int dstIndex)
+ {
+ if (Scope == null)
+ {
+ dst[dstIndex] = unchecked(unchecked(0x00));
+ return 1;
+ }
+ // copy new scope in
+ dst[dstIndex++] = unchecked((byte)('.'));
+ try
+ {
+ Array.Copy(Runtime.GetBytesForString(Scope, OemEncoding
+ ), 0, dst, dstIndex, Scope.Length);
+ }
+ catch (UnsupportedEncodingException)
+ {
+ }
+ dstIndex += Scope.Length;
+ dst[dstIndex++] = unchecked(unchecked(0x00));
+ // now go over scope backwards converting '.' to label length
+ int i = dstIndex - 2;
+ int e = i - Scope.Length;
+ int c = 0;
+ do
+ {
+ if (dst[i] == '.')
+ {
+ dst[i] = unchecked((byte)c);
+ c = 0;
+ }
+ else
+ {
+ c++;
+ }
+ }
+ while (i-- > e);
+ return Scope.Length + 2;
+ }
+
+ internal virtual int ReadScopeWireFormat(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ int n;
+ StringBuilder sb;
+ if ((n = src[srcIndex++] & unchecked(0xFF)) == 0)
+ {
+ Scope = null;
+ return 1;
+ }
+ try
+ {
+ sb = new StringBuilder(Runtime.GetStringForBytes(src, srcIndex, n, OemEncoding));
+ srcIndex += n;
+ while ((n = src[srcIndex++] & unchecked(0xFF)) != 0)
+ {
+ sb.Append('.').Append(Runtime.GetStringForBytes(src, srcIndex, n, OemEncoding));
+ srcIndex += n;
+ }
+ Scope = sb.ToString();
+ }
+ catch (UnsupportedEncodingException)
+ {
+ }
+ return srcIndex - start;
+ }
+
+ public override int GetHashCode()
+ {
+ int result;
+ result = name.GetHashCode();
+ result += 65599 * HexCode;
+ result += 65599 * SrcHashCode;
+ if (Scope != null && Scope.Length != 0)
+ {
+ result += Scope.GetHashCode();
+ }
+ return result;
+ }
+
+ public override bool Equals(object obj)
+ {
+ Name n;
+ if (!(obj is Name))
+ {
+ return false;
+ }
+ n = (Name)obj;
+ if (Scope == null && n.Scope == null)
+ {
+ return name.Equals(n.name) && HexCode == n.HexCode;
+ }
+ return name.Equals(n.name) && HexCode == n.HexCode && Scope.Equals(n.Scope);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ //return "";
+
+ string n = name;
+ // fix MSBROWSE name
+ if (n == null)
+ {
+ n = "null";
+ }
+ else
+ {
+ if (n[0] == unchecked(0x01))
+ {
+ char[] c = n.ToCharArray();
+ c[0] = '.';
+ c[1] = '.';
+ c[14] = '.';
+ n = new string(c);
+ }
+ }
+ sb.Append(n).Append("<").Append(Hexdump.ToHexString(HexCode, 2)).Append(">");
+ if (Scope != null)
+ {
+ sb.Append(".").Append(Scope);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs
new file mode 100644
index 000000000..646e65bf8
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryRequest.cs
@@ -0,0 +1,52 @@
+// 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
+namespace SharpCifs.Netbios
+{
+ internal class NameQueryRequest : NameServicePacket
+ {
+ internal NameQueryRequest(Name name)
+ {
+ QuestionName = name;
+ QuestionType = Nb;
+ }
+
+ internal override int WriteBodyWireFormat(byte[] dst, int dstIndex)
+ {
+ return WriteQuestionSectionWireFormat(dst, dstIndex);
+ }
+
+ internal override int ReadBodyWireFormat(byte[] src, int srcIndex)
+ {
+ return ReadQuestionSectionWireFormat(src, srcIndex);
+ }
+
+ internal override int WriteRDataWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadRDataWireFormat(byte[] src, int srcIndex)
+ {
+ return 0;
+ }
+
+ public override string ToString()
+ {
+ return "NameQueryRequest[" + base.ToString() + "]";
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs
new file mode 100644
index 000000000..c7fac8e93
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameQueryResponse.cs
@@ -0,0 +1,68 @@
+// 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
+namespace SharpCifs.Netbios
+{
+ internal class NameQueryResponse : NameServicePacket
+ {
+ public NameQueryResponse()
+ {
+ RecordName = new Name();
+ }
+
+ internal override int WriteBodyWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadBodyWireFormat(byte[] src, int srcIndex)
+ {
+ return ReadResourceRecordWireFormat(src, srcIndex);
+ }
+
+ internal override int WriteRDataWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadRDataWireFormat(byte[] src, int srcIndex)
+ {
+ if (ResultCode != 0 || OpCode != Query)
+ {
+ return 0;
+ }
+ bool groupName = ((src[srcIndex] & unchecked(0x80)) == unchecked(0x80)) ? true : false;
+ int nodeType = (src[srcIndex] & unchecked(0x60)) >> 5;
+ srcIndex += 2;
+ int address = ReadInt4(src, srcIndex);
+ if (address != 0)
+ {
+ AddrEntry[AddrIndex] = new NbtAddress(RecordName, address, groupName, nodeType);
+ }
+ else
+ {
+ AddrEntry[AddrIndex] = null;
+ }
+ return 6;
+ }
+
+ public override string ToString()
+ {
+ return "NameQueryResponse[" + base.ToString() + ",addrEntry=" + AddrEntry
+ + "]";
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs
new file mode 100644
index 000000000..01700e64a
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs
@@ -0,0 +1,660 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Linq;
+using System.Threading;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+using Thread = SharpCifs.Util.Sharpen.Thread;
+
+namespace SharpCifs.Netbios
+{
+ internal class NameServiceClient : IRunnable
+ {
+ internal const int DefaultSoTimeout = 5000;
+
+ internal const int DefaultRcvBufSize = 576;
+
+ internal const int DefaultSndBufSize = 576;
+
+ internal const int NameServiceUdpPort = 137;
+
+ internal const int DefaultRetryCount = 2;
+
+ internal const int DefaultRetryTimeout = 3000;
+
+ internal const int ResolverLmhosts = 1;
+
+ internal const int ResolverBcast = 2;
+
+ internal const int ResolverWins = 3;
+
+ private static readonly int SndBufSize = Config.GetInt("jcifs.netbios.snd_buf_size"
+ , DefaultSndBufSize);
+
+ private static readonly int RcvBufSize = Config.GetInt("jcifs.netbios.rcv_buf_size"
+ , DefaultRcvBufSize);
+
+ private static readonly int SoTimeout = Config.GetInt("jcifs.netbios.soTimeout",
+ DefaultSoTimeout);
+
+ private static readonly int RetryCount = Config.GetInt("jcifs.netbios.retryCount"
+ , DefaultRetryCount);
+
+ private static readonly int RetryTimeout = Config.GetInt("jcifs.netbios.retryTimeout"
+ , DefaultRetryTimeout);
+
+ private static readonly int Lport = Config.GetInt("jcifs.netbios.lport", 137);
+
+ private static readonly IPAddress Laddr = Config.GetInetAddress("jcifs.netbios.laddr"
+ , null);
+
+ private static readonly string Ro = Config.GetProperty("jcifs.resolveOrder");
+
+ private static LogStream _log = LogStream.GetInstance();
+
+ private readonly object _lock = new object();
+
+ private int _lport;
+
+ private int _closeTimeout;
+
+ private byte[] _sndBuf;
+
+ private byte[] _rcvBuf;
+
+ private SocketEx _socket;
+
+ private Hashtable _responseTable = new Hashtable();
+
+ private Thread _thread;
+
+ private int _nextNameTrnId;
+
+ private int[] _resolveOrder;
+
+ private bool _waitResponse = true;
+
+ private AutoResetEvent _autoResetWaitReceive;
+
+ internal IPAddress laddr;
+
+ internal IPAddress Baddr;
+
+ public NameServiceClient()
+ : this(Lport, Laddr)
+ {
+ }
+
+ internal NameServiceClient(int lport, IPAddress laddr)
+ {
+ this._lport = lport;
+
+ this.laddr = laddr
+ ?? Config.GetLocalHost()
+ ?? Extensions.GetAddressesByName(Dns.GetHostName()).FirstOrDefault();
+
+ try
+ {
+ Baddr = Config.GetInetAddress("jcifs.netbios.baddr", Extensions.GetAddressByName("255.255.255.255"));
+ }
+ catch (Exception ex)
+ {
+ }
+
+ _sndBuf = new byte[SndBufSize];
+ _rcvBuf = new byte[RcvBufSize];
+
+
+ if (string.IsNullOrEmpty(Ro))
+ {
+ if (NbtAddress.GetWinsAddress() == null)
+ {
+ _resolveOrder = new int[2];
+ _resolveOrder[0] = ResolverLmhosts;
+ _resolveOrder[1] = ResolverBcast;
+ }
+ else
+ {
+ _resolveOrder = new int[3];
+ _resolveOrder[0] = ResolverLmhosts;
+ _resolveOrder[1] = ResolverWins;
+ _resolveOrder[2] = ResolverBcast;
+ }
+ }
+ else
+ {
+ int[] tmp = new int[3];
+ 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 (NbtAddress.GetWinsAddress() == null)
+ {
+ if (_log.Level > 1)
+ {
+ _log.WriteLine("NetBIOS 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"))
+ {
+ }
+ else
+ {
+ // skip
+ if (_log.Level > 1)
+ {
+ _log.WriteLine("unknown resolver method: " + s);
+ }
+ }
+ }
+ }
+ }
+ }
+ _resolveOrder = new int[i];
+ Array.Copy(tmp, 0, _resolveOrder, 0, i);
+ }
+ }
+
+ internal virtual int GetNextNameTrnId()
+ {
+ if ((++_nextNameTrnId & unchecked(0xFFFF)) == 0)
+ {
+ _nextNameTrnId = 1;
+ }
+ return _nextNameTrnId;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal virtual void EnsureOpen(int timeout)
+ {
+ _closeTimeout = 0;
+ if (SoTimeout != 0)
+ {
+ _closeTimeout = Math.Max(SoTimeout, timeout);
+ }
+ // If socket is still good, the new closeTimeout will
+ // be ignored; see tryClose comment.
+ if (_socket == null)
+ {
+ _socket = new SocketEx(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+
+ //IPAddress.`Address` property deleted
+ //_socket.Bind(new IPEndPoint(laddr.Address, _lport));
+ _socket.Bind(new IPEndPoint(laddr, _lport));
+
+ if (_waitResponse)
+ {
+ _thread = new Thread(this); //new Sharpen.Thread(this, "JCIFS-NameServiceClient");
+ _thread.SetDaemon(true);
+ _thread.Start();
+ }
+ }
+ }
+
+ internal virtual void TryClose()
+ {
+ lock (_lock)
+ {
+ if (_socket != null)
+ {
+ //Socket.`Close` method deleted
+ //_socket.Close();
+ _socket.Dispose();
+ _socket = null;
+ }
+ _thread = null;
+
+ if (_waitResponse)
+ {
+ _responseTable.Clear();
+ } else
+ {
+ _autoResetWaitReceive.Set();
+ }
+ }
+ }
+
+ public virtual void Run()
+ {
+ int nameTrnId;
+ NameServicePacket response;
+
+ try
+ {
+
+ while (_thread == Thread.CurrentThread())
+ {
+ _socket.SoTimeOut = _closeTimeout;
+
+ int len = _socket.Receive(_rcvBuf, 0, RcvBufSize);
+
+ if (_log.Level > 3)
+ {
+ _log.WriteLine("NetBIOS: new data read from socket");
+ }
+ nameTrnId = NameServicePacket.ReadNameTrnId(_rcvBuf, 0);
+ response = (NameServicePacket)_responseTable.Get(nameTrnId);
+
+
+ if (response == null || response.Received)
+ {
+ continue;
+ }
+
+ lock (response)
+ {
+ response.ReadWireFormat(_rcvBuf, 0);
+
+ if (_log.Level > 3)
+ {
+ _log.WriteLine(response);
+ Hexdump.ToHexdump(_log, _rcvBuf, 0, len);
+ }
+
+ if (response.IsResponse)
+ {
+ response.Received = true;
+
+ Runtime.Notify(response);
+ }
+ }
+ }
+
+ }
+ catch (TimeoutException) { }
+ catch (Exception ex)
+ {
+ if (_log.Level > 2)
+ {
+ Runtime.PrintStackTrace(ex, _log);
+ }
+ }
+ finally
+ {
+ TryClose();
+ }
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal virtual void Send(NameServicePacket request, NameServicePacket response,
+ int timeout)
+ {
+ int nid = 0;
+ int max = NbtAddress.Nbns.Length;
+ if (max == 0)
+ {
+ max = 1;
+ }
+
+ lock (response)
+ {
+
+ while (max-- > 0)
+ {
+ try
+ {
+ lock (_lock)
+ {
+ request.NameTrnId = GetNextNameTrnId();
+ nid = request.NameTrnId;
+ response.Received = false;
+ _responseTable.Put(nid, response);
+ EnsureOpen(timeout + 1000);
+ int requestLenght = request.WriteWireFormat(_sndBuf, 0);
+ _socket.Send(_sndBuf, 0, requestLenght, new IPEndPoint(request.Addr, _lport));
+ if (_log.Level > 3)
+ {
+ _log.WriteLine(request);
+ Hexdump.ToHexdump(_log, _sndBuf, 0, requestLenght);
+ }
+
+ }
+ if (_waitResponse)
+ {
+ long start = Runtime.CurrentTimeMillis();
+ while (timeout > 0)
+ {
+ Runtime.Wait(response, timeout);
+ if (response.Received && request.QuestionType == response.RecordType)
+ {
+ return;
+ }
+ response.Received = false;
+ timeout -= (int)(Runtime.CurrentTimeMillis() - start);
+ }
+ }
+ }
+ catch (Exception ie)
+ {
+ throw new IOException(ie.Message);
+ }
+ finally
+ {
+ //Sharpen.Collections.Remove(responseTable, nid);
+ if (_waitResponse)
+ {
+ _responseTable.Remove(nid);
+ }
+ }
+ if (_waitResponse)
+ {
+ lock (_lock)
+ {
+ if (NbtAddress.IsWins(request.Addr) == false)
+ {
+ break;
+ }
+ if (request.Addr == NbtAddress.GetWinsAddress())
+ {
+ NbtAddress.SwitchWins();
+ }
+ request.Addr = NbtAddress.GetWinsAddress();
+ }
+ }
+ }
+ }
+ }
+
+ /// <exception cref="UnknownHostException"></exception>
+ internal virtual NbtAddress[] GetAllByName(Name name, IPAddress addr)
+ {
+ int n;
+ NameQueryRequest request = new NameQueryRequest(name);
+ NameQueryResponse response = new NameQueryResponse();
+ request.Addr = addr ?? NbtAddress.GetWinsAddress();
+ request.IsBroadcast = request.Addr == null;
+ if (request.IsBroadcast)
+ {
+ request.Addr = Baddr;
+ n = RetryCount;
+ }
+ else
+ {
+ request.IsBroadcast = false;
+ n = 1;
+ }
+ do
+ {
+ try
+ {
+ Send(request, response, RetryTimeout);
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 1)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ throw new UnknownHostException(ioe);
+ }
+ if (response.Received && response.ResultCode == 0)
+ {
+ return response.AddrEntry;
+ }
+ }
+ while (--n > 0 && request.IsBroadcast);
+ throw new UnknownHostException();
+ }
+
+ /// <exception cref="UnknownHostException"></exception>
+ internal virtual NbtAddress GetByName(Name name, IPAddress addr)
+ {
+ int n;
+
+ NameQueryRequest request = new NameQueryRequest(name);
+ NameQueryResponse response = new NameQueryResponse();
+ if (addr != null)
+ {
+ request.Addr = addr;
+ request.IsBroadcast = (addr.GetAddressBytes()[3] == unchecked(unchecked(0xFF)));
+ n = RetryCount;
+ do
+ {
+ try
+ {
+ Send(request, response, RetryTimeout);
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 1)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ throw new UnknownHostException(ioe);
+ }
+ if (response.Received && response.ResultCode == 0
+ && response.IsResponse)
+ {
+ int last = response.AddrEntry.Length - 1;
+ response.AddrEntry[last].HostName.SrcHashCode = addr.GetHashCode();
+ return response.AddrEntry[last];
+ }
+ }
+ while (--n > 0 && request.IsBroadcast);
+ throw new UnknownHostException();
+ }
+ for (int i = 0; i < _resolveOrder.Length; i++)
+ {
+ try
+ {
+ switch (_resolveOrder[i])
+ {
+ case ResolverLmhosts:
+ {
+ NbtAddress ans = Lmhosts.GetByName(name);
+ if (ans != null)
+ {
+ ans.HostName.SrcHashCode = 0;
+ // just has to be different
+ // from other methods
+ return ans;
+ }
+ break;
+ }
+
+ case ResolverWins:
+ case ResolverBcast:
+ {
+ if (_resolveOrder[i] == ResolverWins && name.name != NbtAddress.MasterBrowserName
+ && name.HexCode != unchecked(0x1d))
+ {
+ request.Addr = NbtAddress.GetWinsAddress();
+ request.IsBroadcast = false;
+ }
+ else
+ {
+ request.Addr = Baddr;
+ request.IsBroadcast = true;
+ }
+ n = RetryCount;
+ while (n-- > 0)
+ {
+ try
+ {
+ Send(request, response, RetryTimeout);
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 1)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ throw new UnknownHostException(ioe);
+ }
+ if (response.Received && response.ResultCode == 0
+ && response.IsResponse)
+ {
+
+ response.AddrEntry[0].HostName.SrcHashCode = request.Addr.GetHashCode();
+ return response.AddrEntry[0];
+ }
+ if (_resolveOrder[i] == ResolverWins)
+ {
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ catch (IOException)
+ {
+ }
+ }
+ throw new UnknownHostException();
+ }
+
+ /// <exception cref="UnknownHostException"></exception>
+ internal virtual NbtAddress[] GetNodeStatus(NbtAddress addr)
+ {
+ int n;
+ int srcHashCode;
+ NodeStatusRequest request;
+ NodeStatusResponse response;
+ response = new NodeStatusResponse(addr);
+ request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x00), null));
+ request.Addr = addr.GetInetAddress();
+ n = RetryCount;
+ while (n-- > 0)
+ {
+ try
+ {
+ Send(request, response, RetryTimeout);
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 1)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ throw new UnknownHostException(ioe);
+ }
+ if (response.Received && response.ResultCode == 0)
+ {
+ srcHashCode = request.Addr.GetHashCode();
+ for (int i = 0; i < response.AddressArray.Length; i++)
+ {
+ response.AddressArray[i].HostName.SrcHashCode = srcHashCode;
+ }
+ return response.AddressArray;
+ }
+ }
+ throw new UnknownHostException();
+ }
+
+ internal virtual NbtAddress[] GetHosts()
+ {
+ try
+ {
+ _waitResponse = false;
+
+ byte[] bAddrBytes = laddr.GetAddressBytes();
+
+ for (int i = 1; i <= 254; i++)
+ {
+ NodeStatusRequest request;
+ NodeStatusResponse response;
+
+ byte[] addrBytes = {
+ bAddrBytes[0],
+ bAddrBytes[1],
+ bAddrBytes[2],
+ (byte)i
+ };
+
+ IPAddress addr = new IPAddress(addrBytes);
+
+ //response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
+ // (int)addr.Address, false, 0x20));
+ response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
+ BitConverter.ToInt32(addr.GetAddressBytes(), 0) , false, 0x20));
+
+ request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x20), null));
+ request.Addr = addr;
+ Send(request, response, 0);
+ }
+
+ }
+ catch (IOException ioe)
+ {
+ if (_log.Level > 1)
+ {
+ Runtime.PrintStackTrace(ioe, _log);
+ }
+ throw new UnknownHostException(ioe);
+ }
+
+ _autoResetWaitReceive = new AutoResetEvent(false);
+ _thread = new Thread(this);
+ _thread.SetDaemon(true);
+ _thread.Start();
+
+ _autoResetWaitReceive.WaitOne();
+
+ List<NbtAddress> result = new List<NbtAddress>();
+
+ foreach (var key in _responseTable.Keys)
+ {
+ NodeStatusResponse resp = (NodeStatusResponse)_responseTable[key];
+
+ if (resp.Received && resp.ResultCode == 0)
+ {
+ foreach (var entry in resp.AddressArray)
+ {
+ if (entry.HostName.HexCode == 0x20)
+ {
+ result.Add(entry);
+ }
+ }
+ }
+ }
+
+ _responseTable.Clear();
+
+ _waitResponse = true;
+
+ return result.Count > 0 ? result.ToArray() : null;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs
new file mode 100644
index 000000000..28e98406e
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NameServicePacket.cs
@@ -0,0 +1,448 @@
+// 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.Net;
+using SharpCifs.Util;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ internal abstract class NameServicePacket
+ {
+ internal const int Query = 0;
+
+ internal const int Wack = 7;
+
+ internal const int FmtErr = 0x1;
+
+ internal const int SrvErr = 0x2;
+
+ internal const int ImpErr = 0x4;
+
+ internal const int RfsErr = 0x5;
+
+ internal const int ActErr = 0x6;
+
+ internal const int CftErr = 0x7;
+
+ internal const int NbIn = 0x00200001;
+
+ internal const int NbstatIn = 0x00210001;
+
+ internal const int Nb = 0x0020;
+
+ internal const int Nbstat = 0x0021;
+
+ internal const int In = 0x0001;
+
+ internal const int A = 0x0001;
+
+ internal const int Ns = 0x0002;
+
+ internal const int Null = 0x000a;
+
+ internal const int HeaderLength = 12;
+
+ internal const int OpcodeOffset = 2;
+
+ internal const int QuestionOffset = 4;
+
+ internal const int AnswerOffset = 6;
+
+ internal const int AuthorityOffset = 8;
+
+ internal const int AdditionalOffset = 10;
+
+ // opcode
+ // rcode
+ // type/class
+ // header field offsets
+ internal static void WriteInt2(int val, byte[] dst, int dstIndex)
+ {
+ dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
+ dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
+ }
+
+ internal static void WriteInt4(int val, byte[] dst, int dstIndex)
+ {
+ dst[dstIndex++] = unchecked((byte)((val >> 24) & unchecked(0xFF)));
+ dst[dstIndex++] = unchecked((byte)((val >> 16) & unchecked(0xFF)));
+ dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
+ dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
+ }
+
+ internal static int ReadInt2(byte[] src, int srcIndex)
+ {
+ return ((src[srcIndex] & unchecked(0xFF)) << 8) + (src[srcIndex + 1] & unchecked(
+ 0xFF));
+ }
+
+ internal static int ReadInt4(byte[] src, int srcIndex)
+ {
+ return ((src[srcIndex] & unchecked(0xFF)) << 24) + ((src[srcIndex + 1] & unchecked(
+ 0xFF)) << 16) + ((src[srcIndex + 2] & unchecked(0xFF)) << 8) + (src
+ [srcIndex + 3] & unchecked(0xFF));
+ }
+
+ internal static int ReadNameTrnId(byte[] src, int srcIndex)
+ {
+ return ReadInt2(src, srcIndex);
+ }
+
+ internal int AddrIndex;
+
+ internal NbtAddress[] AddrEntry;
+
+ internal int NameTrnId;
+
+ internal int OpCode;
+
+ internal int ResultCode;
+
+ internal int QuestionCount;
+
+ internal int AnswerCount;
+
+ internal int AuthorityCount;
+
+ internal int AdditionalCount;
+
+ internal bool Received;
+
+ internal bool IsResponse;
+
+ internal bool IsAuthAnswer;
+
+ internal bool IsTruncated;
+
+ internal bool IsRecurDesired;
+
+ internal bool IsRecurAvailable;
+
+ internal bool IsBroadcast;
+
+ internal Name QuestionName;
+
+ internal Name RecordName;
+
+ internal int QuestionType;
+
+ internal int QuestionClass;
+
+ internal int RecordType;
+
+ internal int RecordClass;
+
+ internal int Ttl;
+
+ internal int RDataLength;
+
+ internal IPAddress Addr;
+
+ public NameServicePacket()
+ {
+ IsRecurDesired = true;
+ IsBroadcast = true;
+ QuestionCount = 1;
+ QuestionClass = In;
+ }
+
+ internal virtual int WriteWireFormat(byte[] dst, int dstIndex)
+ {
+ int start = dstIndex;
+ dstIndex += WriteHeaderWireFormat(dst, dstIndex);
+ dstIndex += WriteBodyWireFormat(dst, dstIndex);
+ return dstIndex - start;
+ }
+
+ internal virtual int ReadWireFormat(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ srcIndex += ReadHeaderWireFormat(src, srcIndex);
+ srcIndex += ReadBodyWireFormat(src, srcIndex);
+ return srcIndex - start;
+ }
+
+ internal virtual int WriteHeaderWireFormat(byte[] dst, int dstIndex)
+ {
+ int start = dstIndex;
+ WriteInt2(NameTrnId, dst, dstIndex);
+ dst[dstIndex + OpcodeOffset] = unchecked((byte)((IsResponse ? unchecked(0x80) : unchecked(0x00)) + ((OpCode << 3) & unchecked(0x78)) + (IsAuthAnswer
+ ? unchecked(0x04) : unchecked(0x00)) + (IsTruncated ? unchecked(0x02) : unchecked(0x00)) + (IsRecurDesired ? unchecked(0x01)
+ : unchecked(0x00))));
+ dst[dstIndex + OpcodeOffset + 1] = unchecked((byte)((IsRecurAvailable ? unchecked(
+ 0x80) : unchecked(0x00)) + (IsBroadcast ? unchecked(0x10) :
+ unchecked(0x00)) + (ResultCode & unchecked(0x0F))));
+ WriteInt2(QuestionCount, dst, start + QuestionOffset);
+ WriteInt2(AnswerCount, dst, start + AnswerOffset);
+ WriteInt2(AuthorityCount, dst, start + AuthorityOffset);
+ WriteInt2(AdditionalCount, dst, start + AdditionalOffset);
+ return HeaderLength;
+ }
+
+ internal virtual int ReadHeaderWireFormat(byte[] src, int srcIndex)
+ {
+ NameTrnId = ReadInt2(src, srcIndex);
+ IsResponse = ((src[srcIndex + OpcodeOffset] & unchecked(0x80)) == 0) ? false
+ : true;
+ OpCode = (src[srcIndex + OpcodeOffset] & unchecked(0x78)) >> 3;
+ IsAuthAnswer = ((src[srcIndex + OpcodeOffset] & unchecked(0x04)) == 0) ?
+ false : true;
+ IsTruncated = ((src[srcIndex + OpcodeOffset] & unchecked(0x02)) == 0) ? false
+ : true;
+ IsRecurDesired = ((src[srcIndex + OpcodeOffset] & unchecked(0x01)) == 0) ?
+ false : true;
+ IsRecurAvailable = ((src[srcIndex + OpcodeOffset + 1] & unchecked(0x80))
+ == 0) ? false : true;
+ IsBroadcast = ((src[srcIndex + OpcodeOffset + 1] & unchecked(0x10)) == 0)
+ ? false : true;
+ ResultCode = src[srcIndex + OpcodeOffset + 1] & unchecked(0x0F);
+ QuestionCount = ReadInt2(src, srcIndex + QuestionOffset);
+ AnswerCount = ReadInt2(src, srcIndex + AnswerOffset);
+ AuthorityCount = ReadInt2(src, srcIndex + AuthorityOffset);
+ AdditionalCount = ReadInt2(src, srcIndex + AdditionalOffset);
+ return HeaderLength;
+ }
+
+ internal virtual int WriteQuestionSectionWireFormat(byte[] dst, int dstIndex)
+ {
+ int start = dstIndex;
+ dstIndex += QuestionName.WriteWireFormat(dst, dstIndex);
+ WriteInt2(QuestionType, dst, dstIndex);
+ dstIndex += 2;
+ WriteInt2(QuestionClass, dst, dstIndex);
+ dstIndex += 2;
+ return dstIndex - start;
+ }
+
+ internal virtual int ReadQuestionSectionWireFormat(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ srcIndex += QuestionName.ReadWireFormat(src, srcIndex);
+ QuestionType = ReadInt2(src, srcIndex);
+ srcIndex += 2;
+ QuestionClass = ReadInt2(src, srcIndex);
+ srcIndex += 2;
+ return srcIndex - start;
+ }
+
+ internal virtual int WriteResourceRecordWireFormat(byte[] dst, int dstIndex)
+ {
+ int start = dstIndex;
+ if (RecordName == QuestionName)
+ {
+ dst[dstIndex++] = unchecked(unchecked(0xC0));
+ // label string pointer to
+ dst[dstIndex++] = unchecked(unchecked(0x0C));
+ }
+ else
+ {
+ // questionName (offset 12)
+ dstIndex += RecordName.WriteWireFormat(dst, dstIndex);
+ }
+ WriteInt2(RecordType, dst, dstIndex);
+ dstIndex += 2;
+ WriteInt2(RecordClass, dst, dstIndex);
+ dstIndex += 2;
+ WriteInt4(Ttl, dst, dstIndex);
+ dstIndex += 4;
+ RDataLength = WriteRDataWireFormat(dst, dstIndex + 2);
+ WriteInt2(RDataLength, dst, dstIndex);
+ dstIndex += 2 + RDataLength;
+ return dstIndex - start;
+ }
+
+ internal virtual int ReadResourceRecordWireFormat(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ int end;
+ if ((src[srcIndex] & unchecked(0xC0)) == unchecked(0xC0))
+ {
+ RecordName = QuestionName;
+ // label string pointer to questionName
+ srcIndex += 2;
+ }
+ else
+ {
+ srcIndex += RecordName.ReadWireFormat(src, srcIndex);
+ }
+ RecordType = ReadInt2(src, srcIndex);
+ srcIndex += 2;
+ RecordClass = ReadInt2(src, srcIndex);
+ srcIndex += 2;
+ Ttl = ReadInt4(src, srcIndex);
+ srcIndex += 4;
+ RDataLength = ReadInt2(src, srcIndex);
+ srcIndex += 2;
+ AddrEntry = new NbtAddress[RDataLength / 6];
+ end = srcIndex + RDataLength;
+ for (AddrIndex = 0; srcIndex < end; AddrIndex++)
+ {
+ srcIndex += ReadRDataWireFormat(src, srcIndex);
+ }
+ return srcIndex - start;
+ }
+
+ internal abstract int WriteBodyWireFormat(byte[] dst, int dstIndex);
+
+ internal abstract int ReadBodyWireFormat(byte[] src, int srcIndex);
+
+ internal abstract int WriteRDataWireFormat(byte[] dst, int dstIndex);
+
+ internal abstract int ReadRDataWireFormat(byte[] src, int srcIndex);
+
+ public override string ToString()
+ {
+ string opCodeString;
+ string resultCodeString;
+ string questionTypeString;
+ string recordTypeString;
+
+ switch (OpCode)
+ {
+ case Query:
+ {
+ opCodeString = "QUERY";
+ break;
+ }
+
+ case Wack:
+ {
+ opCodeString = "WACK";
+ break;
+ }
+
+ default:
+ {
+ opCodeString = Extensions.ToString(OpCode);
+ break;
+ }
+ }
+ switch (ResultCode)
+ {
+ case FmtErr:
+ {
+ resultCodeString = "FMT_ERR";
+ break;
+ }
+
+ case SrvErr:
+ {
+ resultCodeString = "SRV_ERR";
+ break;
+ }
+
+ case ImpErr:
+ {
+ resultCodeString = "IMP_ERR";
+ break;
+ }
+
+ case RfsErr:
+ {
+ resultCodeString = "RFS_ERR";
+ break;
+ }
+
+ case ActErr:
+ {
+ resultCodeString = "ACT_ERR";
+ break;
+ }
+
+ case CftErr:
+ {
+ resultCodeString = "CFT_ERR";
+ break;
+ }
+
+ default:
+ {
+ resultCodeString = "0x" + Hexdump.ToHexString(ResultCode, 1);
+ break;
+ }
+ }
+ switch (QuestionType)
+ {
+ case Nb:
+ {
+ questionTypeString = "NB";
+ break;
+ }
+
+ case Nbstat:
+ {
+ questionTypeString = "NBSTAT";
+ break;
+ }
+
+ default:
+ {
+ questionTypeString = "0x" + Hexdump.ToHexString(QuestionType, 4);
+ break;
+ }
+ }
+ switch (RecordType)
+ {
+ case A:
+ {
+ recordTypeString = "A";
+ break;
+ }
+
+ case Ns:
+ {
+ recordTypeString = "NS";
+ break;
+ }
+
+ case Null:
+ {
+ recordTypeString = "NULL";
+ break;
+ }
+
+ case Nb:
+ {
+ recordTypeString = "NB";
+ break;
+ }
+
+ case Nbstat:
+ {
+ recordTypeString = "NBSTAT";
+ break;
+ }
+
+ default:
+ {
+ recordTypeString = "0x" + Hexdump.ToHexString(RecordType, 4);
+ break;
+ }
+ }
+ return "nameTrnId=" + NameTrnId + ",isResponse=" + IsResponse + ",opCode="
+ + opCodeString + ",isAuthAnswer=" + IsAuthAnswer + ",isTruncated=" + IsTruncated
+ + ",isRecurAvailable=" + IsRecurAvailable + ",isRecurDesired=" + IsRecurDesired
+ + ",isBroadcast=" + IsBroadcast + ",resultCode=" + ResultCode + ",questionCount="
+ + QuestionCount + ",answerCount=" + AnswerCount + ",authorityCount=" + AuthorityCount
+ + ",additionalCount=" + AdditionalCount + ",questionName=" + QuestionName + ",questionType="
+ + questionTypeString + ",questionClass=" + (QuestionClass == In ? "IN" : "0x" +
+ Hexdump.ToHexString(QuestionClass, 4)) + ",recordName=" + RecordName + ",recordType="
+ + recordTypeString + ",recordClass=" + (RecordClass == In ? "IN" : "0x" + Hexdump
+ .ToHexString(RecordClass, 4)) + ",ttl=" + Ttl + ",rDataLength=" + RDataLength;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs
new file mode 100644
index 000000000..c64d385f1
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtAddress.cs
@@ -0,0 +1,920 @@
+// 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:\&gt;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. &lt;a
+ /// href="../../../nbtcodes.html"&gt;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();
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs
new file mode 100644
index 000000000..e785c9943
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NbtException.cs
@@ -0,0 +1,164 @@
+// 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.IO;
+
+namespace SharpCifs.Netbios
+{
+
+ public class NbtException : IOException
+ {
+ public const int Success = 0;
+
+ public const int ErrNamSrvc = unchecked(0x01);
+
+ public const int ErrSsnSrvc = unchecked(0x02);
+
+ public const int FmtErr = unchecked(0x1);
+
+ public const int SrvErr = unchecked(0x2);
+
+ public const int ImpErr = unchecked(0x4);
+
+ public const int RfsErr = unchecked(0x5);
+
+ public const int ActErr = unchecked(0x6);
+
+ public const int CftErr = unchecked(0x7);
+
+ public const int ConnectionRefused = -1;
+
+ public const int NotListeningCalled = unchecked(0x80);
+
+ public const int NotListeningCalling = unchecked(0x81);
+
+ public const int CalledNotPresent = unchecked(0x82);
+
+ public const int NoResources = unchecked(0x83);
+
+ public const int Unspecified = unchecked(0x8F);
+
+ public int ErrorClass;
+
+ public int ErrorCode;
+
+ // error classes
+ // name service error codes
+ // session service error codes
+ public static string GetErrorString(int errorClass, int errorCode)
+ {
+ string result = string.Empty;
+ switch (errorClass)
+ {
+ case Success:
+ {
+ result += "SUCCESS";
+ break;
+ }
+
+ case ErrNamSrvc:
+ {
+ result += "ERR_NAM_SRVC/";
+ switch (errorCode)
+ {
+ case FmtErr:
+ {
+ result += "FMT_ERR: Format Error";
+ goto default;
+ }
+
+ default:
+ {
+ result += "Unknown error code: " + errorCode;
+ break;
+ }
+ }
+ break;
+ }
+
+ case ErrSsnSrvc:
+ {
+ result += "ERR_SSN_SRVC/";
+ switch (errorCode)
+ {
+ case ConnectionRefused:
+ {
+ result += "Connection refused";
+ break;
+ }
+
+ case NotListeningCalled:
+ {
+ result += "Not listening on called name";
+ break;
+ }
+
+ case NotListeningCalling:
+ {
+ result += "Not listening for calling name";
+ break;
+ }
+
+ case CalledNotPresent:
+ {
+ result += "Called name not present";
+ break;
+ }
+
+ case NoResources:
+ {
+ result += "Called name present, but insufficient resources";
+ break;
+ }
+
+ case Unspecified:
+ {
+ result += "Unspecified error";
+ break;
+ }
+
+ default:
+ {
+ result += "Unknown error code: " + errorCode;
+ break;
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ result += "unknown error class: " + errorClass;
+ break;
+ }
+ }
+ return result;
+ }
+
+ public NbtException(int errorClass, int errorCode) : base(GetErrorString(errorClass
+ , errorCode))
+ {
+ this.ErrorClass = errorClass;
+ this.ErrorCode = errorCode;
+ }
+
+ public override string ToString()
+ {
+ return "errorClass=" + ErrorClass + ",errorCode=" + ErrorCode + ",errorString="
+ + GetErrorString(ErrorClass, ErrorCode);
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs
new file mode 100644
index 000000000..66d3bb3e5
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusRequest.cs
@@ -0,0 +1,59 @@
+// 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
+namespace SharpCifs.Netbios
+{
+ internal class NodeStatusRequest : NameServicePacket
+ {
+ internal NodeStatusRequest(Name name)
+ {
+ QuestionName = name;
+ QuestionType = Nbstat;
+ IsRecurDesired = false;
+ IsBroadcast = false;
+ }
+
+ internal override int WriteBodyWireFormat(byte[] dst, int dstIndex)
+ {
+ int tmp = QuestionName.HexCode;
+ QuestionName.HexCode = unchecked(0x00);
+ // type has to be 0x00 for node status
+ int result = WriteQuestionSectionWireFormat(dst, dstIndex);
+ QuestionName.HexCode = tmp;
+ return result;
+ }
+
+ internal override int ReadBodyWireFormat(byte[] src, int srcIndex)
+ {
+ return 0;
+ }
+
+ internal override int WriteRDataWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadRDataWireFormat(byte[] src, int srcIndex)
+ {
+ return 0;
+ }
+
+ public override string ToString()
+ {
+ return "NodeStatusRequest[" + base.ToString() + "]";
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs
new file mode 100644
index 000000000..aa3214419
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/NodeStatusResponse.cs
@@ -0,0 +1,140 @@
+// 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 SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ internal class NodeStatusResponse : NameServicePacket
+ {
+ private NbtAddress _queryAddress;
+
+ private int _numberOfNames;
+
+ private byte[] _macAddress;
+
+ private byte[] _stats;
+
+ internal NbtAddress[] AddressArray;
+
+ internal NodeStatusResponse(NbtAddress queryAddress)
+ {
+ this._queryAddress = queryAddress;
+ RecordName = new Name();
+ _macAddress = new byte[6];
+ }
+
+ internal override int WriteBodyWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadBodyWireFormat(byte[] src, int srcIndex)
+ {
+ return ReadResourceRecordWireFormat(src, srcIndex);
+ }
+
+ internal override int WriteRDataWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ internal override int ReadRDataWireFormat(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ _numberOfNames = src[srcIndex] & unchecked(0xFF);
+ int namesLength = _numberOfNames * 18;
+ int statsLength = RDataLength - namesLength - 1;
+ _numberOfNames = src[srcIndex++] & unchecked(0xFF);
+ // gotta read the mac first so we can populate addressArray with it
+ Array.Copy(src, srcIndex + namesLength, _macAddress, 0, 6);
+ srcIndex += ReadNodeNameArray(src, srcIndex);
+ _stats = new byte[statsLength];
+ Array.Copy(src, srcIndex, _stats, 0, statsLength);
+ srcIndex += statsLength;
+ return srcIndex - start;
+ }
+
+ private int ReadNodeNameArray(byte[] src, int srcIndex)
+ {
+ int start = srcIndex;
+ AddressArray = new NbtAddress[_numberOfNames];
+ string n;
+ int hexCode;
+ string scope = _queryAddress.HostName.Scope;
+ bool groupName;
+ int ownerNodeType;
+ bool isBeingDeleted;
+ bool isInConflict;
+ bool isActive;
+ bool isPermanent;
+ int j;
+ bool addrFound = false;
+ try
+ {
+ for (int i = 0; i < _numberOfNames; srcIndex += 18, i++)
+ {
+ for (j = srcIndex + 14; src[j] == unchecked(0x20); j--)
+ {
+ }
+ n = Runtime.GetStringForBytes(src, srcIndex, j - srcIndex + 1, Name.OemEncoding
+ );
+ hexCode = src[srcIndex + 15] & unchecked(0xFF);
+ groupName = ((src[srcIndex + 16] & unchecked(0x80)) == unchecked(0x80)) ? true : false;
+ ownerNodeType = (src[srcIndex + 16] & unchecked(0x60)) >> 5;
+ isBeingDeleted = ((src[srcIndex + 16] & unchecked(0x10)) == unchecked(0x10)) ? true : false;
+ isInConflict = ((src[srcIndex + 16] & unchecked(0x08)) == unchecked(0x08)) ? true : false;
+ isActive = ((src[srcIndex + 16] & unchecked(0x04)) == unchecked(0x04)) ? true : false;
+ isPermanent = ((src[srcIndex + 16] & unchecked(0x02)) == unchecked(0x02)) ? true : false;
+ if (!addrFound && _queryAddress.HostName.HexCode == hexCode && (_queryAddress.HostName
+ == NbtAddress.UnknownName || _queryAddress.HostName.name.Equals(n)))
+ {
+ if (_queryAddress.HostName == NbtAddress.UnknownName)
+ {
+ _queryAddress.HostName = new Name(n, hexCode, scope);
+ }
+ _queryAddress.GroupName = groupName;
+ _queryAddress.NodeType = ownerNodeType;
+ _queryAddress.isBeingDeleted = isBeingDeleted;
+ _queryAddress.isInConflict = isInConflict;
+ _queryAddress.isActive = isActive;
+ _queryAddress.isPermanent = isPermanent;
+ _queryAddress.MacAddress = _macAddress;
+ _queryAddress.IsDataFromNodeStatus = true;
+ addrFound = true;
+ AddressArray[i] = _queryAddress;
+ }
+ else
+ {
+ AddressArray[i] = new NbtAddress(new Name(n, hexCode, scope), _queryAddress.Address
+ , groupName, ownerNodeType, isBeingDeleted, isInConflict, isActive, isPermanent,
+ _macAddress);
+ }
+ }
+ }
+ catch (UnsupportedEncodingException)
+ {
+ }
+ return srcIndex - start;
+ }
+
+ public override string ToString()
+ {
+ return "NodeStatusResponse[" + base.ToString() + "]";
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs
new file mode 100644
index 000000000..a5243f7aa
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRequestPacket.cs
@@ -0,0 +1,63 @@
+// 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.IO;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ public class SessionRequestPacket : SessionServicePacket
+ {
+ private Name _calledName;
+
+ private Name _callingName;
+
+ public SessionRequestPacket()
+ {
+ _calledName = new Name();
+ _callingName = new Name();
+ }
+
+ public SessionRequestPacket(Name calledName, Name callingName)
+ {
+ Type = SessionRequest;
+ this._calledName = calledName;
+ this._callingName = callingName;
+ }
+
+ internal override int WriteTrailerWireFormat(byte[] dst, int dstIndex)
+ {
+ int start = dstIndex;
+ dstIndex += _calledName.WriteWireFormat(dst, dstIndex);
+ dstIndex += _callingName.WriteWireFormat(dst, dstIndex);
+ return dstIndex - start;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal override int ReadTrailerWireFormat(InputStream @in, byte[] buffer, int bufferIndex
+ )
+ {
+ int start = bufferIndex;
+ if (@in.Read(buffer, bufferIndex, Length) != Length)
+ {
+ throw new IOException("invalid session request wire format");
+ }
+ bufferIndex += _calledName.ReadWireFormat(buffer, bufferIndex);
+ bufferIndex += _callingName.ReadWireFormat(buffer, bufferIndex);
+ return bufferIndex - start;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs
new file mode 100644
index 000000000..c901c6e26
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionRetargetResponsePacket.cs
@@ -0,0 +1,54 @@
+// 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.IO;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ internal class SessionRetargetResponsePacket : SessionServicePacket
+ {
+ private NbtAddress _retargetAddress;
+
+ private int _retargetPort;
+
+ public SessionRetargetResponsePacket()
+ {
+ Type = SessionRetargetResponse;
+ Length = 6;
+ }
+
+ internal override int WriteTrailerWireFormat(byte[] dst, int dstIndex)
+ {
+ return 0;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal override int ReadTrailerWireFormat(InputStream @in, byte[] buffer, int bufferIndex
+ )
+ {
+ if (@in.Read(buffer, bufferIndex, Length) != Length)
+ {
+ throw new IOException("unexpected EOF reading netbios retarget session response");
+ }
+ int addr = ReadInt4(buffer, bufferIndex);
+ bufferIndex += 4;
+ _retargetAddress = new NbtAddress(null, addr, false, NbtAddress.BNode);
+ _retargetPort = ReadInt2(buffer, bufferIndex);
+ return Length;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs
new file mode 100644
index 000000000..c8d194222
--- /dev/null
+++ b/Emby.Server.Implementations/IO/SharpCifs/Netbios/SessionServicePacket.cs
@@ -0,0 +1,156 @@
+// 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.IO;
+using SharpCifs.Util.Sharpen;
+
+namespace SharpCifs.Netbios
+{
+ public abstract class SessionServicePacket
+ {
+ internal const int SessionMessage = unchecked(0x00);
+
+ internal const int SessionRequest = unchecked(0x81);
+
+ public const int PositiveSessionResponse = unchecked(0x82);
+
+ public const int NegativeSessionResponse = unchecked(0x83);
+
+ internal const int SessionRetargetResponse = unchecked(0x84);
+
+ internal const int SessionKeepAlive = unchecked(0x85);
+
+ internal const int MaxMessageSize = unchecked(0x0001FFFF);
+
+ internal const int HeaderLength = 4;
+
+ // session service packet types
+ internal static void WriteInt2(int val, byte[] dst, int dstIndex)
+ {
+ dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
+ dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
+ }
+
+ internal static void WriteInt4(int val, byte[] dst, int dstIndex)
+ {
+ dst[dstIndex++] = unchecked((byte)((val >> 24) & unchecked(0xFF)));
+ dst[dstIndex++] = unchecked((byte)((val >> 16) & unchecked(0xFF)));
+ dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
+ dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
+ }
+
+ internal static int ReadInt2(byte[] src, int srcIndex)
+ {
+ return ((src[srcIndex] & unchecked(0xFF)) << 8) + (src[srcIndex + 1] & unchecked(
+ 0xFF));
+ }
+
+ internal static int ReadInt4(byte[] src, int srcIndex)
+ {
+ return ((src[srcIndex] & unchecked(0xFF)) << 24) + ((src[srcIndex + 1] & unchecked(
+ 0xFF)) << 16) + ((src[srcIndex + 2] & unchecked(0xFF)) << 8) + (src
+ [srcIndex + 3] & unchecked(0xFF));
+ }
+
+ internal static int ReadLength(byte[] src, int srcIndex)
+ {
+ srcIndex++;
+ return ((src[srcIndex++] & unchecked(0x01)) << 16) + ((src[srcIndex++] & unchecked(
+ 0xFF)) << 8) + (src[srcIndex++] & unchecked(0xFF));
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal static int Readn(InputStream @in, byte[] b, int off, int len)
+ {
+ int i = 0;
+ int n;
+ while (i < len)
+ {
+ n = @in.Read(b, off + i, len - i);
+ if (n <= 0)
+ {
+ break;
+ }
+ i += n;
+ }
+ return i;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal static int ReadPacketType(InputStream @in, byte[] buffer, int bufferIndex
+ )
+ {
+ int n;
+ if ((n = Readn(@in, buffer, bufferIndex, HeaderLength)) != HeaderLength)
+ {
+ if (n == -1)
+ {
+ return -1;
+ }
+ throw new IOException("unexpected EOF reading netbios session header");
+ }
+ int t = buffer[bufferIndex] & unchecked(0xFF);
+ return t;
+ }
+
+ internal int Type;
+
+ internal int Length;
+
+ public virtual int WriteWireFormat(byte[] dst, int dstIndex)
+ {
+ Length = WriteTrailerWireFormat(dst, dstIndex + HeaderLength);
+ WriteHeaderWireFormat(dst, dstIndex);
+ return HeaderLength + Length;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal virtual int ReadWireFormat(InputStream @in, byte[] buffer, int bufferIndex
+ )
+ {
+ ReadHeaderWireFormat(@in, buffer, bufferIndex);
+ return HeaderLength + ReadTrailerWireFormat(@in, buffer, bufferIndex);
+ }
+
+ internal virtual int WriteHeaderWireFormat(byte[] dst, int dstIndex)
+ {
+ dst[dstIndex++] = unchecked((byte)Type);
+ if (Length > unchecked(0x0000FFFF))
+ {
+ dst[dstIndex] = unchecked(unchecked(0x01));
+ }
+ dstIndex++;
+ WriteInt2(Length, dst, dstIndex);
+ return HeaderLength;
+ }
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal virtual int ReadHeaderWireFormat(InputStream @in, byte[] buffer, int bufferIndex
+ )
+ {
+ Type = buffer[bufferIndex++] & unchecked(0xFF);
+ Length = ((buffer[bufferIndex] & unchecked(0x01)) << 16) + ReadInt2(buffer
+ , bufferIndex + 1);
+ return HeaderLength;
+ }
+
+ internal abstract int WriteTrailerWireFormat(byte[] dst, int dstIndex);
+
+ /// <exception cref="System.IO.IOException"></exception>
+ internal abstract int ReadTrailerWireFormat(InputStream @in, byte[] buffer, int bufferIndex
+ );
+ }
+}