diff options
Diffstat (limited to 'Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs')
| -rw-r--r-- | Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs | 318 |
1 files changed, 236 insertions, 82 deletions
diff --git a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs b/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs index 01700e64a..fb74c691b 100644 --- a/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs +++ b/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs @@ -21,10 +21,13 @@ using System.Net; using System.Net.Sockets; using System.Linq; using System.Threading; +using SharpCifs.Smb; using SharpCifs.Util; +using SharpCifs.Util.DbsHelper; using SharpCifs.Util.Sharpen; using Thread = SharpCifs.Util.Sharpen.Thread; +using System.Threading.Tasks; namespace SharpCifs.Netbios { @@ -48,27 +51,29 @@ namespace SharpCifs.Netbios internal const int ResolverWins = 3; - private static readonly int SndBufSize = Config.GetInt("jcifs.netbios.snd_buf_size" - , DefaultSndBufSize); + 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 RcvBufSize + = Config.GetInt("jcifs.netbios.rcv_buf_size", DefaultRcvBufSize); - private static readonly int SoTimeout = Config.GetInt("jcifs.netbios.soTimeout", - DefaultSoTimeout); + 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 RetryCount + = Config.GetInt("jcifs.netbios.retryCount", DefaultRetryCount); - private static readonly int RetryTimeout = Config.GetInt("jcifs.netbios.retryTimeout" - , DefaultRetryTimeout); + 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 int Lport + = Config.GetInt("jcifs.netbios.lport", 137); - private static readonly IPAddress Laddr = Config.GetInetAddress("jcifs.netbios.laddr" - , null); + private static readonly IPAddress Laddr + = Config.GetInetAddress("jcifs.netbios.laddr", null); - private static readonly string Ro = Config.GetProperty("jcifs.resolveOrder"); + private static readonly string Ro + = Config.GetProperty("jcifs.resolveOrder"); private static LogStream _log = LogStream.GetInstance(); @@ -82,18 +87,20 @@ namespace SharpCifs.Netbios private byte[] _rcvBuf; - private SocketEx _socket; + private SocketEx _socketSender; private Hashtable _responseTable = new Hashtable(); private Thread _thread; - + private int _nextNameTrnId; private int[] _resolveOrder; private bool _waitResponse = true; + private bool _isActive = false; + private AutoResetEvent _autoResetWaitReceive; internal IPAddress laddr; @@ -109,13 +116,17 @@ namespace SharpCifs.Netbios { this._lport = lport; - this.laddr = laddr - ?? Config.GetLocalHost() - ?? Extensions.GetAddressesByName(Dns.GetHostName()).FirstOrDefault(); + this.laddr = laddr + ?? Config.GetLocalHost() + ?? Extensions.GetLocalAddresses()?.FirstOrDefault(); + + if (this.laddr == null) + throw new ArgumentNullException("IPAddress NOT found. if exec on localhost, set vallue to [jcifs.smb.client.laddr]"); try { - Baddr = Config.GetInetAddress("jcifs.netbios.baddr", Extensions.GetAddressByName("255.255.255.255")); + Baddr = Config.GetInetAddress("jcifs.netbios.baddr", + Extensions.GetAddressByName("255.255.255.255")); } catch (Exception ex) { @@ -161,8 +172,8 @@ namespace SharpCifs.Netbios { if (_log.Level > 1) { - _log.WriteLine("NetBIOS resolveOrder specifies WINS however the " + "jcifs.netbios.wins property has not been set" - ); + _log.WriteLine("NetBIOS resolveOrder specifies WINS however the " + + "jcifs.netbios.wins property has not been set"); } continue; } @@ -208,53 +219,93 @@ namespace SharpCifs.Netbios /// <exception cref="System.IO.IOException"></exception> internal virtual void EnsureOpen(int timeout) { + //Log.Out($"NameServiceClient.EnsureOpen"); + _closeTimeout = 0; if (SoTimeout != 0) { _closeTimeout = Math.Max(SoTimeout, timeout); } + + var localPort = (SmbConstants.Lport == 0) ? _lport : SmbConstants.Lport; + // If socket is still good, the new closeTimeout will // be ignored; see tryClose comment. - if (_socket == null) + if ( + _socketSender == null + || _socketSender.LocalEndPoint == null + || _socketSender.GetLocalPort() != localPort + || !IPAddress.Any.Equals(_socketSender.GetLocalInetAddress()) + ) { - _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 (_socketSender != null) + { + _socketSender.Dispose(); + _socketSender = null; + } + + _socketSender = new SocketEx(AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + + _socketSender.Bind(new IPEndPoint(IPAddress.Any, localPort)); + if (_waitResponse) { - _thread = new Thread(this); //new Sharpen.Thread(this, "JCIFS-NameServiceClient"); + if (_thread != null) + { + _thread.Cancel(true); + _thread.Dispose(); + } + + _thread = new Thread(this); _thread.SetDaemon(true); - _thread.Start(); + _thread.Start(true); } } } internal virtual void TryClose() { + //Log.Out("NameSerciceClient.TryClose"); + + if (this._isActive) + { + //Log.Out("NameSerciceClient.TryClose - Now in Processing... Exit."); + return; + } + lock (_lock) { - if (_socket != null) + if (_socketSender != null) { - //Socket.`Close` method deleted - //_socket.Close(); - _socket.Dispose(); - _socket = null; + _socketSender.Dispose(); + _socketSender = null; + //Log.Out("NameSerciceClient.TryClose - _socketSender.Disposed"); + } + + if (_thread != null) + { + _thread.Cancel(true); + _thread.Dispose(); + _thread = null; + //Log.Out("NameSerciceClient.TryClose - _thread.Aborted"); } - _thread = null; if (_waitResponse) { _responseTable.Clear(); - } else + } + else { _autoResetWaitReceive.Set(); } } } + + private int _recievedLength = -1; public virtual void Run() { int nameTrnId; @@ -262,12 +313,38 @@ namespace SharpCifs.Netbios try { - - while (_thread == Thread.CurrentThread()) + while (Thread.CurrentThread().Equals(_thread)) { - _socket.SoTimeOut = _closeTimeout; + if (_thread.IsCanceled) + break; + + var localPort = (SmbConstants.Lport == 0) ? _lport : SmbConstants.Lport; + + var sockEvArg = new SocketAsyncEventArgs(); + sockEvArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, localPort); + sockEvArg.SetBuffer(_rcvBuf, 0, RcvBufSize); + sockEvArg.Completed += this.OnReceiveCompleted; + + _socketSender.SoTimeOut = _closeTimeout; + + this._recievedLength = -1; + + //Log.Out($"NameServiceClient.Run - Wait Recieve: {IPAddress.Any}: {localPort}"); + _socketSender.ReceiveFromAsync(sockEvArg); + + while (this._recievedLength == -1) + { + if (_thread.IsCanceled) + break; + + Task.Delay(300).GetAwaiter().GetResult(); + } + + sockEvArg?.Dispose(); - int len = _socket.Receive(_rcvBuf, 0, RcvBufSize); + + if (_thread.IsCanceled) + break; if (_log.Level > 3) { @@ -284,12 +361,15 @@ namespace SharpCifs.Netbios lock (response) { + if (_thread.IsCanceled) + break; + response.ReadWireFormat(_rcvBuf, 0); if (_log.Level > 3) { _log.WriteLine(response); - Hexdump.ToHexdump(_log, _rcvBuf, 0, len); + Hexdump.ToHexdump(_log, _rcvBuf, 0, this._recievedLength); } if (response.IsResponse) @@ -300,7 +380,6 @@ namespace SharpCifs.Netbios } } } - } catch (TimeoutException) { } catch (Exception ex) @@ -316,10 +395,21 @@ namespace SharpCifs.Netbios } } + + private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e) + { + //Log.Out("NameServiceClient.OnReceiveCompleted"); + this._recievedLength = e.BytesTransferred; + } + + /// <exception cref="System.IO.IOException"></exception> - internal virtual void Send(NameServicePacket request, NameServicePacket response, - int timeout) + internal virtual void Send(NameServicePacket request, + NameServicePacket response, + int timeout) { + //Log.Out("NameSerciceClient.Send - Start"); + int nid = 0; int max = NbtAddress.Nbns.Length; if (max == 0) @@ -329,6 +419,7 @@ namespace SharpCifs.Netbios lock (response) { + this._isActive = true; while (max-- > 0) { @@ -338,45 +429,75 @@ namespace SharpCifs.Netbios { request.NameTrnId = GetNextNameTrnId(); nid = request.NameTrnId; + response.Received = false; _responseTable.Put(nid, response); + + //Log.Out($"NameSerciceClient.Send - timeout = {timeout}"); EnsureOpen(timeout + 1000); + int requestLenght = request.WriteWireFormat(_sndBuf, 0); - _socket.Send(_sndBuf, 0, requestLenght, new IPEndPoint(request.Addr, _lport)); + byte[] msg = new byte[requestLenght]; + Array.Copy(_sndBuf, msg, requestLenght); + + _socketSender.SetSocketOption(SocketOptionLevel.Socket, + SocketOptionName.Broadcast, + request.IsBroadcast + ? 1 + : 0); + + _socketSender.SendTo(msg, new IPEndPoint(request.Addr, _lport)); + //Log.Out("NameSerciceClient.Send - Sended"); + if (_log.Level > 3) { _log.WriteLine(request); Hexdump.ToHexdump(_log, _sndBuf, 0, requestLenght); } - } + if (_waitResponse) { long start = Runtime.CurrentTimeMillis(); + var isRecieved = false; + var startTime = DateTime.Now; while (timeout > 0) { Runtime.Wait(response, timeout); if (response.Received && request.QuestionType == response.RecordType) { - return; + //return; + isRecieved = true; + break; } response.Received = false; timeout -= (int)(Runtime.CurrentTimeMillis() - start); + + //if (timeout <= 0) + //{ + // Log.Out($"NameSerciceClient.Send Timeout! - {(DateTime.Now - startTime).TotalMilliseconds} msec"); + //} } + + if (isRecieved) + break; } } catch (Exception ie) { + if (_waitResponse) + _responseTable.Remove(nid); + + //Log.Out("NameSerciceClient.Send - IOException"); + throw new IOException(ie.Message); } finally { - //Sharpen.Collections.Remove(responseTable, nid); if (_waitResponse) - { _responseTable.Remove(nid); - } } + if (_waitResponse) { lock (_lock) @@ -393,17 +514,24 @@ namespace SharpCifs.Netbios } } } + + this._isActive = false; + //Log.Out("NameSerciceClient.Send - Normaly Ended."); } } /// <exception cref="UnknownHostException"></exception> internal virtual NbtAddress[] GetAllByName(Name name, IPAddress addr) { + //Log.Out("NameSerciceClient.GetAllByName"); + int n; NameQueryRequest request = new NameQueryRequest(name); NameQueryResponse response = new NameQueryResponse(); request.Addr = addr ?? NbtAddress.GetWinsAddress(); - request.IsBroadcast = request.Addr == null; + request.IsBroadcast = (request.Addr == null + || request.Addr.ToString() == Baddr.ToString()); + if (request.IsBroadcast) { request.Addr = Baddr; @@ -440,10 +568,12 @@ namespace SharpCifs.Netbios /// <exception cref="UnknownHostException"></exception> internal virtual NbtAddress GetByName(Name name, IPAddress addr) { - int n; + //Log.Out("NameSerciceClient.GetByName"); + int n; NameQueryRequest request = new NameQueryRequest(name); NameQueryResponse response = new NameQueryResponse(); + if (addr != null) { request.Addr = addr; @@ -463,7 +593,9 @@ namespace SharpCifs.Netbios } throw new UnknownHostException(ioe); } - if (response.Received && response.ResultCode == 0 + + if (response.Received + && response.ResultCode == 0 && response.IsResponse) { int last = response.AddrEntry.Length - 1; @@ -471,9 +603,11 @@ namespace SharpCifs.Netbios return response.AddrEntry[last]; } } + while (--n > 0 && request.IsBroadcast); throw new UnknownHostException(); } + for (int i = 0; i < _resolveOrder.Length; i++) { try @@ -496,8 +630,9 @@ namespace SharpCifs.Netbios case ResolverWins: case ResolverBcast: { - if (_resolveOrder[i] == ResolverWins && name.name != NbtAddress.MasterBrowserName - && name.HexCode != unchecked(0x1d)) + if (_resolveOrder[i] == ResolverWins + && name.name != NbtAddress.MasterBrowserName + && name.HexCode != unchecked(0x1d)) { request.Addr = NbtAddress.GetWinsAddress(); request.IsBroadcast = false; @@ -522,11 +657,12 @@ namespace SharpCifs.Netbios } throw new UnknownHostException(ioe); } - if (response.Received && response.ResultCode == 0 + if (response.Received + && response.ResultCode == 0 && response.IsResponse) { - - response.AddrEntry[0].HostName.SrcHashCode = request.Addr.GetHashCode(); + response.AddrEntry[0].HostName.SrcHashCode + = request.Addr.GetHashCode(); return response.AddrEntry[0]; } if (_resolveOrder[i] == ResolverWins) @@ -542,12 +678,15 @@ namespace SharpCifs.Netbios { } } + throw new UnknownHostException(); } /// <exception cref="UnknownHostException"></exception> internal virtual NbtAddress[] GetNodeStatus(NbtAddress addr) { + //Log.Out("NameSerciceClient.GetNodeStatus"); + int n; int srcHashCode; NodeStatusRequest request; @@ -556,6 +695,7 @@ namespace SharpCifs.Netbios request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x00), null)); request.Addr = addr.GetInetAddress(); n = RetryCount; + while (n-- > 0) { try @@ -585,6 +725,8 @@ namespace SharpCifs.Netbios internal virtual NbtAddress[] GetHosts() { + //Log.Out("NbtServiceClient.GetHosts"); + try { _waitResponse = false; @@ -593,6 +735,8 @@ namespace SharpCifs.Netbios for (int i = 1; i <= 254; i++) { + //Log.Out($"NbtServiceClient.GetHosts - {i}"); + NodeStatusRequest request; NodeStatusResponse response; @@ -605,49 +749,59 @@ namespace SharpCifs.Netbios 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)); + response = new NodeStatusResponse( + new NbtAddress(NbtAddress.UnknownName, + BitConverter.ToInt32(addr.GetAddressBytes(), 0), + false, + 0x20) + ); + + request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, + unchecked(0x20), + null)) + { + Addr = addr + }; - request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x20), null)); - request.Addr = addr; Send(request, response, 0); } - } catch (IOException ioe) { + //Log.Out(ioe); + if (_log.Level > 1) { Runtime.PrintStackTrace(ioe, _log); } throw new UnknownHostException(ioe); } - + _autoResetWaitReceive = new AutoResetEvent(false); - _thread = new Thread(this); + + if (_thread != null) + { + _thread.Cancel(true); + _thread.Dispose(); + } + + _thread = new Thread(this); _thread.SetDaemon(true); - _thread.Start(); + _thread.Start(true); - _autoResetWaitReceive.WaitOne(); + _autoResetWaitReceive.WaitOne(); - List<NbtAddress> result = new List<NbtAddress>(); + var result = new List<NbtAddress>(); foreach (var key in _responseTable.Keys) { - NodeStatusResponse resp = (NodeStatusResponse)_responseTable[key]; + var resp = (NodeStatusResponse)_responseTable[key]; - if (resp.Received && resp.ResultCode == 0) - { - foreach (var entry in resp.AddressArray) - { - if (entry.HostName.HexCode == 0x20) - { - result.Add(entry); - } - } - } + if (!resp.Received || resp.ResultCode != 0) + continue; + + result.AddRange(resp.AddressArray + .Where(entry => entry.HostName.HexCode == 0x20)); } _responseTable.Clear(); |
