jellyfin-server/Emby.Common.Implementations/IO/SharpCifs/Netbios/NameServiceClient.cs

815 lines
28 KiB
C#
Raw Normal View History

2017-04-02 00:36:06 +00:00
// 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;
2017-06-21 06:46:57 +00:00
using SharpCifs.Smb;
2017-04-02 00:36:06 +00:00
using SharpCifs.Util;
2017-06-21 06:46:57 +00:00
using SharpCifs.Util.DbsHelper;
2017-04-02 00:36:06 +00:00
using SharpCifs.Util.Sharpen;
using Thread = SharpCifs.Util.Sharpen.Thread;
2017-06-21 06:46:57 +00:00
using System.Threading.Tasks;
2017-04-02 00:36:06 +00:00
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;
2017-06-21 06:46:57 +00:00
private static readonly int SndBufSize
= Config.GetInt("jcifs.netbios.snd_buf_size", DefaultSndBufSize);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly int RcvBufSize
= Config.GetInt("jcifs.netbios.rcv_buf_size", DefaultRcvBufSize);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly int SoTimeout
= Config.GetInt("jcifs.netbios.soTimeout", DefaultSoTimeout);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly int RetryCount
= Config.GetInt("jcifs.netbios.retryCount", DefaultRetryCount);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly int RetryTimeout
= Config.GetInt("jcifs.netbios.retryTimeout", DefaultRetryTimeout);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly int Lport
= Config.GetInt("jcifs.netbios.lport", 137);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly IPAddress Laddr
= Config.GetInetAddress("jcifs.netbios.laddr", null);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
private static readonly string Ro
= Config.GetProperty("jcifs.resolveOrder");
2017-04-02 00:36:06 +00:00
private static LogStream _log = LogStream.GetInstance();
private readonly object _lock = new object();
private int _lport;
private int _closeTimeout;
private byte[] _sndBuf;
private byte[] _rcvBuf;
2017-06-21 06:46:57 +00:00
private SocketEx _socketSender;
2017-04-02 00:36:06 +00:00
private Hashtable _responseTable = new Hashtable();
private Thread _thread;
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
private int _nextNameTrnId;
private int[] _resolveOrder;
private bool _waitResponse = true;
2017-06-21 06:46:57 +00:00
private bool _isActive = false;
2017-04-02 00:36:06 +00:00
private AutoResetEvent _autoResetWaitReceive;
internal IPAddress laddr;
internal IPAddress Baddr;
public NameServiceClient()
: this(Lport, Laddr)
{
}
internal NameServiceClient(int lport, IPAddress laddr)
{
this._lport = lport;
2017-06-21 06:46:57 +00:00
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]");
2017-04-02 00:36:06 +00:00
try
{
2017-06-21 06:46:57 +00:00
Baddr = Config.GetInetAddress("jcifs.netbios.baddr",
Extensions.GetAddressByName("255.255.255.255"));
2017-04-02 00:36:06 +00:00
}
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)
{
2017-06-21 06:46:57 +00:00
_log.WriteLine("NetBIOS resolveOrder specifies WINS however the "
+ "jcifs.netbios.wins property has not been set");
2017-04-02 00:36:06 +00:00
}
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)
{
2017-06-21 06:46:57 +00:00
//Log.Out($"NameServiceClient.EnsureOpen");
2017-04-02 00:36:06 +00:00
_closeTimeout = 0;
if (SoTimeout != 0)
{
_closeTimeout = Math.Max(SoTimeout, timeout);
}
2017-06-21 06:46:57 +00:00
var localPort = (SmbConstants.Lport == 0) ? _lport : SmbConstants.Lport;
2017-04-02 00:36:06 +00:00
// If socket is still good, the new closeTimeout will
// be ignored; see tryClose comment.
2017-06-21 06:46:57 +00:00
if (
_socketSender == null
|| _socketSender.LocalEndPoint == null
|| _socketSender.GetLocalPort() != localPort
|| !IPAddress.Any.Equals(_socketSender.GetLocalInetAddress())
)
2017-04-02 00:36:06 +00:00
{
2017-06-21 06:46:57 +00:00
if (_socketSender != null)
{
_socketSender.Dispose();
_socketSender = null;
}
_socketSender = new SocketEx(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
_socketSender.Bind(new IPEndPoint(IPAddress.Any, localPort));
2017-04-02 00:36:06 +00:00
if (_waitResponse)
{
2017-06-21 06:46:57 +00:00
if (_thread != null)
{
_thread.Cancel(true);
_thread.Dispose();
}
_thread = new Thread(this);
2017-04-02 00:36:06 +00:00
_thread.SetDaemon(true);
2017-06-21 06:46:57 +00:00
_thread.Start(true);
2017-04-02 00:36:06 +00:00
}
}
}
internal virtual void TryClose()
{
2017-06-21 06:46:57 +00:00
//Log.Out("NameSerciceClient.TryClose");
if (this._isActive)
{
//Log.Out("NameSerciceClient.TryClose - Now in Processing... Exit.");
return;
}
2017-04-02 00:36:06 +00:00
lock (_lock)
{
2017-06-21 06:46:57 +00:00
if (_socketSender != null)
2017-04-02 00:36:06 +00:00
{
2017-06-21 06:46:57 +00:00
_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");
2017-04-02 00:36:06 +00:00
}
if (_waitResponse)
{
_responseTable.Clear();
2017-06-21 06:46:57 +00:00
}
else
2017-04-02 00:36:06 +00:00
{
_autoResetWaitReceive.Set();
}
}
}
2017-06-21 06:46:57 +00:00
private int _recievedLength = -1;
2017-04-02 00:36:06 +00:00
public virtual void Run()
{
int nameTrnId;
NameServicePacket response;
try
{
2017-06-21 06:46:57 +00:00
while (Thread.CurrentThread().Equals(_thread))
2017-04-02 00:36:06 +00:00
{
2017-06-21 06:46:57 +00:00
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();
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
if (_thread.IsCanceled)
break;
2017-04-02 00:36:06 +00:00
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)
{
2017-06-21 06:46:57 +00:00
if (_thread.IsCanceled)
break;
2017-04-02 00:36:06 +00:00
response.ReadWireFormat(_rcvBuf, 0);
if (_log.Level > 3)
{
_log.WriteLine(response);
2017-06-21 06:46:57 +00:00
Hexdump.ToHexdump(_log, _rcvBuf, 0, this._recievedLength);
2017-04-02 00:36:06 +00:00
}
if (response.IsResponse)
{
response.Received = true;
Runtime.Notify(response);
}
}
}
}
catch (TimeoutException) { }
catch (Exception ex)
{
if (_log.Level > 2)
{
Runtime.PrintStackTrace(ex, _log);
}
}
finally
{
TryClose();
}
}
2017-06-21 06:46:57 +00:00
private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
{
//Log.Out("NameServiceClient.OnReceiveCompleted");
this._recievedLength = e.BytesTransferred;
}
2017-04-02 00:36:06 +00:00
/// <exception cref="System.IO.IOException"></exception>
2017-06-21 06:46:57 +00:00
internal virtual void Send(NameServicePacket request,
NameServicePacket response,
int timeout)
2017-04-02 00:36:06 +00:00
{
2017-06-21 06:46:57 +00:00
//Log.Out("NameSerciceClient.Send - Start");
2017-04-02 00:36:06 +00:00
int nid = 0;
int max = NbtAddress.Nbns.Length;
if (max == 0)
{
max = 1;
}
lock (response)
{
2017-06-21 06:46:57 +00:00
this._isActive = true;
2017-04-02 00:36:06 +00:00
while (max-- > 0)
{
try
{
lock (_lock)
{
request.NameTrnId = GetNextNameTrnId();
nid = request.NameTrnId;
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
response.Received = false;
_responseTable.Put(nid, response);
2017-06-21 06:46:57 +00:00
//Log.Out($"NameSerciceClient.Send - timeout = {timeout}");
2017-04-02 00:36:06 +00:00
EnsureOpen(timeout + 1000);
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
int requestLenght = request.WriteWireFormat(_sndBuf, 0);
2017-06-21 06:46:57 +00:00
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");
2017-04-02 00:36:06 +00:00
if (_log.Level > 3)
{
_log.WriteLine(request);
Hexdump.ToHexdump(_log, _sndBuf, 0, requestLenght);
}
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
if (_waitResponse)
{
long start = Runtime.CurrentTimeMillis();
2017-06-21 06:46:57 +00:00
var isRecieved = false;
var startTime = DateTime.Now;
2017-04-02 00:36:06 +00:00
while (timeout > 0)
{
Runtime.Wait(response, timeout);
if (response.Received && request.QuestionType == response.RecordType)
{
2017-06-21 06:46:57 +00:00
//return;
isRecieved = true;
break;
2017-04-02 00:36:06 +00:00
}
response.Received = false;
timeout -= (int)(Runtime.CurrentTimeMillis() - start);
2017-06-21 06:46:57 +00:00
//if (timeout <= 0)
//{
// Log.Out($"NameSerciceClient.Send Timeout! - {(DateTime.Now - startTime).TotalMilliseconds} msec");
//}
2017-04-02 00:36:06 +00:00
}
2017-06-21 06:46:57 +00:00
if (isRecieved)
break;
2017-04-02 00:36:06 +00:00
}
}
catch (Exception ie)
{
2017-06-21 06:46:57 +00:00
if (_waitResponse)
_responseTable.Remove(nid);
//Log.Out("NameSerciceClient.Send - IOException");
2017-04-02 00:36:06 +00:00
throw new IOException(ie.Message);
}
finally
{
if (_waitResponse)
_responseTable.Remove(nid);
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
if (_waitResponse)
{
lock (_lock)
{
if (NbtAddress.IsWins(request.Addr) == false)
{
break;
}
if (request.Addr == NbtAddress.GetWinsAddress())
{
NbtAddress.SwitchWins();
}
request.Addr = NbtAddress.GetWinsAddress();
}
}
}
2017-06-21 06:46:57 +00:00
this._isActive = false;
//Log.Out("NameSerciceClient.Send - Normaly Ended.");
2017-04-02 00:36:06 +00:00
}
}
/// <exception cref="UnknownHostException"></exception>
internal virtual NbtAddress[] GetAllByName(Name name, IPAddress addr)
{
2017-06-21 06:46:57 +00:00
//Log.Out("NameSerciceClient.GetAllByName");
2017-04-02 00:36:06 +00:00
int n;
NameQueryRequest request = new NameQueryRequest(name);
NameQueryResponse response = new NameQueryResponse();
request.Addr = addr ?? NbtAddress.GetWinsAddress();
2017-06-21 06:46:57 +00:00
request.IsBroadcast = (request.Addr == null
|| request.Addr.ToString() == Baddr.ToString());
2017-04-02 00:36:06 +00:00
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)
{
2017-06-21 06:46:57 +00:00
//Log.Out("NameSerciceClient.GetByName");
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
int n;
2017-04-02 00:36:06 +00:00
NameQueryRequest request = new NameQueryRequest(name);
NameQueryResponse response = new NameQueryResponse();
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
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);
}
2017-06-21 06:46:57 +00:00
if (response.Received
&& response.ResultCode == 0
2017-04-02 00:36:06 +00:00
&& response.IsResponse)
{
int last = response.AddrEntry.Length - 1;
response.AddrEntry[last].HostName.SrcHashCode = addr.GetHashCode();
return response.AddrEntry[last];
}
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
while (--n > 0 && request.IsBroadcast);
throw new UnknownHostException();
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
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:
{
2017-06-21 06:46:57 +00:00
if (_resolveOrder[i] == ResolverWins
&& name.name != NbtAddress.MasterBrowserName
&& name.HexCode != unchecked(0x1d))
2017-04-02 00:36:06 +00:00
{
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);
}
2017-06-21 06:46:57 +00:00
if (response.Received
&& response.ResultCode == 0
2017-04-02 00:36:06 +00:00
&& response.IsResponse)
{
2017-06-21 06:46:57 +00:00
response.AddrEntry[0].HostName.SrcHashCode
= request.Addr.GetHashCode();
2017-04-02 00:36:06 +00:00
return response.AddrEntry[0];
}
if (_resolveOrder[i] == ResolverWins)
{
break;
}
}
break;
}
}
}
catch (IOException)
{
}
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
throw new UnknownHostException();
}
/// <exception cref="UnknownHostException"></exception>
internal virtual NbtAddress[] GetNodeStatus(NbtAddress addr)
{
2017-06-21 06:46:57 +00:00
//Log.Out("NameSerciceClient.GetNodeStatus");
2017-04-02 00:36:06 +00:00
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;
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
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()
{
2017-06-21 06:46:57 +00:00
//Log.Out("NbtServiceClient.GetHosts");
2017-04-02 00:36:06 +00:00
try
{
_waitResponse = false;
byte[] bAddrBytes = laddr.GetAddressBytes();
for (int i = 1; i <= 254; i++)
{
2017-06-21 06:46:57 +00:00
//Log.Out($"NbtServiceClient.GetHosts - {i}");
2017-04-02 00:36:06 +00:00
NodeStatusRequest request;
NodeStatusResponse response;
byte[] addrBytes = {
bAddrBytes[0],
bAddrBytes[1],
bAddrBytes[2],
(byte)i
};
IPAddress addr = new IPAddress(addrBytes);
2017-06-21 06:46:57 +00:00
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
};
2017-04-02 00:36:06 +00:00
Send(request, response, 0);
}
}
catch (IOException ioe)
{
2017-06-21 06:46:57 +00:00
//Log.Out(ioe);
2017-04-02 00:36:06 +00:00
if (_log.Level > 1)
{
Runtime.PrintStackTrace(ioe, _log);
}
throw new UnknownHostException(ioe);
}
2017-06-21 06:46:57 +00:00
2017-04-02 00:36:06 +00:00
_autoResetWaitReceive = new AutoResetEvent(false);
2017-06-21 06:46:57 +00:00
if (_thread != null)
{
_thread.Cancel(true);
_thread.Dispose();
}
_thread = new Thread(this);
2017-04-02 00:36:06 +00:00
_thread.SetDaemon(true);
2017-06-21 06:46:57 +00:00
_thread.Start(true);
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
_autoResetWaitReceive.WaitOne();
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
var result = new List<NbtAddress>();
2017-04-02 00:36:06 +00:00
foreach (var key in _responseTable.Keys)
{
2017-06-21 06:46:57 +00:00
var resp = (NodeStatusResponse)_responseTable[key];
2017-04-02 00:36:06 +00:00
2017-06-21 06:46:57 +00:00
if (!resp.Received || resp.ResultCode != 0)
continue;
result.AddRange(resp.AddressArray
.Where(entry => entry.HostName.HexCode == 0x20));
2017-04-02 00:36:06 +00:00
}
_responseTable.Clear();
_waitResponse = true;
return result.Count > 0 ? result.ToArray() : null;
}
}
}