NameServiceClient.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System;
  18. using System.Collections.Generic;
  19. using System.IO;
  20. using System.Net;
  21. using System.Net.Sockets;
  22. using System.Linq;
  23. using System.Threading;
  24. using SharpCifs.Util;
  25. using SharpCifs.Util.Sharpen;
  26. using Thread = SharpCifs.Util.Sharpen.Thread;
  27. namespace SharpCifs.Netbios
  28. {
  29. internal class NameServiceClient : IRunnable
  30. {
  31. internal const int DefaultSoTimeout = 5000;
  32. internal const int DefaultRcvBufSize = 576;
  33. internal const int DefaultSndBufSize = 576;
  34. internal const int NameServiceUdpPort = 137;
  35. internal const int DefaultRetryCount = 2;
  36. internal const int DefaultRetryTimeout = 3000;
  37. internal const int ResolverLmhosts = 1;
  38. internal const int ResolverBcast = 2;
  39. internal const int ResolverWins = 3;
  40. private static readonly int SndBufSize = Config.GetInt("jcifs.netbios.snd_buf_size"
  41. , DefaultSndBufSize);
  42. private static readonly int RcvBufSize = Config.GetInt("jcifs.netbios.rcv_buf_size"
  43. , DefaultRcvBufSize);
  44. private static readonly int SoTimeout = Config.GetInt("jcifs.netbios.soTimeout",
  45. DefaultSoTimeout);
  46. private static readonly int RetryCount = Config.GetInt("jcifs.netbios.retryCount"
  47. , DefaultRetryCount);
  48. private static readonly int RetryTimeout = Config.GetInt("jcifs.netbios.retryTimeout"
  49. , DefaultRetryTimeout);
  50. private static readonly int Lport = Config.GetInt("jcifs.netbios.lport", 137);
  51. private static readonly IPAddress Laddr = Config.GetInetAddress("jcifs.netbios.laddr"
  52. , null);
  53. private static readonly string Ro = Config.GetProperty("jcifs.resolveOrder");
  54. private static LogStream _log = LogStream.GetInstance();
  55. private readonly object _lock = new object();
  56. private int _lport;
  57. private int _closeTimeout;
  58. private byte[] _sndBuf;
  59. private byte[] _rcvBuf;
  60. private SocketEx _socket;
  61. private Hashtable _responseTable = new Hashtable();
  62. private Thread _thread;
  63. private int _nextNameTrnId;
  64. private int[] _resolveOrder;
  65. private bool _waitResponse = true;
  66. private AutoResetEvent _autoResetWaitReceive;
  67. internal IPAddress laddr;
  68. internal IPAddress Baddr;
  69. public NameServiceClient()
  70. : this(Lport, Laddr)
  71. {
  72. }
  73. internal NameServiceClient(int lport, IPAddress laddr)
  74. {
  75. this._lport = lport;
  76. this.laddr = laddr
  77. ?? Config.GetLocalHost()
  78. ?? Extensions.GetAddressesByName(Dns.GetHostName()).FirstOrDefault();
  79. try
  80. {
  81. Baddr = Config.GetInetAddress("jcifs.netbios.baddr", Extensions.GetAddressByName("255.255.255.255"));
  82. }
  83. catch (Exception)
  84. {
  85. }
  86. _sndBuf = new byte[SndBufSize];
  87. _rcvBuf = new byte[RcvBufSize];
  88. if (string.IsNullOrEmpty(Ro))
  89. {
  90. if (NbtAddress.GetWinsAddress() == null)
  91. {
  92. _resolveOrder = new int[2];
  93. _resolveOrder[0] = ResolverLmhosts;
  94. _resolveOrder[1] = ResolverBcast;
  95. }
  96. else
  97. {
  98. _resolveOrder = new int[3];
  99. _resolveOrder[0] = ResolverLmhosts;
  100. _resolveOrder[1] = ResolverWins;
  101. _resolveOrder[2] = ResolverBcast;
  102. }
  103. }
  104. else
  105. {
  106. int[] tmp = new int[3];
  107. StringTokenizer st = new StringTokenizer(Ro, ",");
  108. int i = 0;
  109. while (st.HasMoreTokens())
  110. {
  111. string s = st.NextToken().Trim();
  112. if (Runtime.EqualsIgnoreCase(s, "LMHOSTS"))
  113. {
  114. tmp[i++] = ResolverLmhosts;
  115. }
  116. else
  117. {
  118. if (Runtime.EqualsIgnoreCase(s, "WINS"))
  119. {
  120. if (NbtAddress.GetWinsAddress() == null)
  121. {
  122. if (_log.Level > 1)
  123. {
  124. _log.WriteLine("NetBIOS resolveOrder specifies WINS however the " + "jcifs.netbios.wins property has not been set"
  125. );
  126. }
  127. continue;
  128. }
  129. tmp[i++] = ResolverWins;
  130. }
  131. else
  132. {
  133. if (Runtime.EqualsIgnoreCase(s, "BCAST"))
  134. {
  135. tmp[i++] = ResolverBcast;
  136. }
  137. else
  138. {
  139. if (Runtime.EqualsIgnoreCase(s, "DNS"))
  140. {
  141. }
  142. else
  143. {
  144. // skip
  145. if (_log.Level > 1)
  146. {
  147. _log.WriteLine("unknown resolver method: " + s);
  148. }
  149. }
  150. }
  151. }
  152. }
  153. }
  154. _resolveOrder = new int[i];
  155. Array.Copy(tmp, 0, _resolveOrder, 0, i);
  156. }
  157. }
  158. internal virtual int GetNextNameTrnId()
  159. {
  160. if ((++_nextNameTrnId & unchecked(0xFFFF)) == 0)
  161. {
  162. _nextNameTrnId = 1;
  163. }
  164. return _nextNameTrnId;
  165. }
  166. /// <exception cref="System.IO.IOException"></exception>
  167. internal virtual void EnsureOpen(int timeout)
  168. {
  169. _closeTimeout = 0;
  170. if (SoTimeout != 0)
  171. {
  172. _closeTimeout = Math.Max(SoTimeout, timeout);
  173. }
  174. // If socket is still good, the new closeTimeout will
  175. // be ignored; see tryClose comment.
  176. if (_socket == null)
  177. {
  178. _socket = new SocketEx(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  179. //IPAddress.`Address` property deleted
  180. //_socket.Bind(new IPEndPoint(laddr.Address, _lport));
  181. _socket.Bind(new IPEndPoint(laddr, _lport));
  182. if (_waitResponse)
  183. {
  184. _thread = new Thread(this); //new Sharpen.Thread(this, "JCIFS-NameServiceClient");
  185. _thread.SetDaemon(true);
  186. _thread.Start();
  187. }
  188. }
  189. }
  190. internal virtual void TryClose()
  191. {
  192. lock (_lock)
  193. {
  194. if (_socket != null)
  195. {
  196. //Socket.`Close` method deleted
  197. //_socket.Close();
  198. _socket.Dispose();
  199. _socket = null;
  200. }
  201. _thread = null;
  202. if (_waitResponse)
  203. {
  204. _responseTable.Clear();
  205. } else
  206. {
  207. _autoResetWaitReceive.Set();
  208. }
  209. }
  210. }
  211. public virtual void Run()
  212. {
  213. int nameTrnId;
  214. NameServicePacket response;
  215. try
  216. {
  217. while (_thread == Thread.CurrentThread())
  218. {
  219. _socket.SoTimeOut = _closeTimeout;
  220. int len = _socket.Receive(_rcvBuf, 0, RcvBufSize);
  221. if (_log.Level > 3)
  222. {
  223. _log.WriteLine("NetBIOS: new data read from socket");
  224. }
  225. nameTrnId = NameServicePacket.ReadNameTrnId(_rcvBuf, 0);
  226. response = (NameServicePacket)_responseTable.Get(nameTrnId);
  227. if (response == null || response.Received)
  228. {
  229. continue;
  230. }
  231. lock (response)
  232. {
  233. response.ReadWireFormat(_rcvBuf, 0);
  234. if (_log.Level > 3)
  235. {
  236. _log.WriteLine(response);
  237. Hexdump.ToHexdump(_log, _rcvBuf, 0, len);
  238. }
  239. if (response.IsResponse)
  240. {
  241. response.Received = true;
  242. Runtime.Notify(response);
  243. }
  244. }
  245. }
  246. }
  247. catch (TimeoutException)
  248. {
  249. }
  250. catch (Exception ex)
  251. {
  252. if (_log.Level > 2)
  253. {
  254. Runtime.PrintStackTrace(ex, _log);
  255. }
  256. }
  257. finally
  258. {
  259. TryClose();
  260. }
  261. }
  262. /// <exception cref="System.IO.IOException"></exception>
  263. internal virtual void Send(NameServicePacket request, NameServicePacket response,
  264. int timeout)
  265. {
  266. int nid = 0;
  267. int max = NbtAddress.Nbns.Length;
  268. if (max == 0)
  269. {
  270. max = 1;
  271. }
  272. lock (response)
  273. {
  274. while (max-- > 0)
  275. {
  276. try
  277. {
  278. lock (_lock)
  279. {
  280. request.NameTrnId = GetNextNameTrnId();
  281. nid = request.NameTrnId;
  282. response.Received = false;
  283. _responseTable.Put(nid, response);
  284. EnsureOpen(timeout + 1000);
  285. int requestLenght = request.WriteWireFormat(_sndBuf, 0);
  286. _socket.Send(_sndBuf, 0, requestLenght, new IPEndPoint(request.Addr, _lport));
  287. if (_log.Level > 3)
  288. {
  289. _log.WriteLine(request);
  290. Hexdump.ToHexdump(_log, _sndBuf, 0, requestLenght);
  291. }
  292. }
  293. if (_waitResponse)
  294. {
  295. long start = Runtime.CurrentTimeMillis();
  296. while (timeout > 0)
  297. {
  298. Runtime.Wait(response, timeout);
  299. if (response.Received && request.QuestionType == response.RecordType)
  300. {
  301. return;
  302. }
  303. response.Received = false;
  304. timeout -= (int)(Runtime.CurrentTimeMillis() - start);
  305. }
  306. }
  307. }
  308. catch (Exception ie)
  309. {
  310. throw new IOException(ie.Message);
  311. }
  312. finally
  313. {
  314. //Sharpen.Collections.Remove(responseTable, nid);
  315. if (_waitResponse)
  316. {
  317. _responseTable.Remove(nid);
  318. }
  319. }
  320. if (_waitResponse)
  321. {
  322. lock (_lock)
  323. {
  324. if (NbtAddress.IsWins(request.Addr) == false)
  325. {
  326. break;
  327. }
  328. if (request.Addr == NbtAddress.GetWinsAddress())
  329. {
  330. NbtAddress.SwitchWins();
  331. }
  332. request.Addr = NbtAddress.GetWinsAddress();
  333. }
  334. }
  335. }
  336. }
  337. }
  338. /// <exception cref="UnknownHostException"></exception>
  339. internal virtual NbtAddress[] GetAllByName(Name name, IPAddress addr)
  340. {
  341. int n;
  342. NameQueryRequest request = new NameQueryRequest(name);
  343. NameQueryResponse response = new NameQueryResponse();
  344. request.Addr = addr ?? NbtAddress.GetWinsAddress();
  345. request.IsBroadcast = request.Addr == null;
  346. if (request.IsBroadcast)
  347. {
  348. request.Addr = Baddr;
  349. n = RetryCount;
  350. }
  351. else
  352. {
  353. request.IsBroadcast = false;
  354. n = 1;
  355. }
  356. do
  357. {
  358. try
  359. {
  360. Send(request, response, RetryTimeout);
  361. }
  362. catch (IOException ioe)
  363. {
  364. if (_log.Level > 1)
  365. {
  366. Runtime.PrintStackTrace(ioe, _log);
  367. }
  368. throw new UnknownHostException(ioe);
  369. }
  370. if (response.Received && response.ResultCode == 0)
  371. {
  372. return response.AddrEntry;
  373. }
  374. }
  375. while (--n > 0 && request.IsBroadcast);
  376. throw new UnknownHostException();
  377. }
  378. /// <exception cref="UnknownHostException"></exception>
  379. internal virtual NbtAddress GetByName(Name name, IPAddress addr)
  380. {
  381. int n;
  382. NameQueryRequest request = new NameQueryRequest(name);
  383. NameQueryResponse response = new NameQueryResponse();
  384. if (addr != null)
  385. {
  386. request.Addr = addr;
  387. request.IsBroadcast = (addr.GetAddressBytes()[3] == unchecked(unchecked(0xFF)));
  388. n = RetryCount;
  389. do
  390. {
  391. try
  392. {
  393. Send(request, response, RetryTimeout);
  394. }
  395. catch (IOException ioe)
  396. {
  397. if (_log.Level > 1)
  398. {
  399. Runtime.PrintStackTrace(ioe, _log);
  400. }
  401. throw new UnknownHostException(ioe);
  402. }
  403. if (response.Received && response.ResultCode == 0
  404. && response.IsResponse)
  405. {
  406. int last = response.AddrEntry.Length - 1;
  407. response.AddrEntry[last].HostName.SrcHashCode = addr.GetHashCode();
  408. return response.AddrEntry[last];
  409. }
  410. }
  411. while (--n > 0 && request.IsBroadcast);
  412. throw new UnknownHostException();
  413. }
  414. for (int i = 0; i < _resolveOrder.Length; i++)
  415. {
  416. try
  417. {
  418. switch (_resolveOrder[i])
  419. {
  420. case ResolverLmhosts:
  421. {
  422. NbtAddress ans = Lmhosts.GetByName(name);
  423. if (ans != null)
  424. {
  425. ans.HostName.SrcHashCode = 0;
  426. // just has to be different
  427. // from other methods
  428. return ans;
  429. }
  430. break;
  431. }
  432. case ResolverWins:
  433. case ResolverBcast:
  434. {
  435. if (_resolveOrder[i] == ResolverWins && name.name != NbtAddress.MasterBrowserName
  436. && name.HexCode != unchecked(0x1d))
  437. {
  438. request.Addr = NbtAddress.GetWinsAddress();
  439. request.IsBroadcast = false;
  440. }
  441. else
  442. {
  443. request.Addr = Baddr;
  444. request.IsBroadcast = true;
  445. }
  446. n = RetryCount;
  447. while (n-- > 0)
  448. {
  449. try
  450. {
  451. Send(request, response, RetryTimeout);
  452. }
  453. catch (IOException ioe)
  454. {
  455. if (_log.Level > 1)
  456. {
  457. Runtime.PrintStackTrace(ioe, _log);
  458. }
  459. throw new UnknownHostException(ioe);
  460. }
  461. if (response.Received && response.ResultCode == 0
  462. && response.IsResponse)
  463. {
  464. response.AddrEntry[0].HostName.SrcHashCode = request.Addr.GetHashCode();
  465. return response.AddrEntry[0];
  466. }
  467. if (_resolveOrder[i] == ResolverWins)
  468. {
  469. break;
  470. }
  471. }
  472. break;
  473. }
  474. }
  475. }
  476. catch (IOException)
  477. {
  478. }
  479. }
  480. throw new UnknownHostException();
  481. }
  482. /// <exception cref="UnknownHostException"></exception>
  483. internal virtual NbtAddress[] GetNodeStatus(NbtAddress addr)
  484. {
  485. int n;
  486. int srcHashCode;
  487. NodeStatusRequest request;
  488. NodeStatusResponse response;
  489. response = new NodeStatusResponse(addr);
  490. request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x00), null));
  491. request.Addr = addr.GetInetAddress();
  492. n = RetryCount;
  493. while (n-- > 0)
  494. {
  495. try
  496. {
  497. Send(request, response, RetryTimeout);
  498. }
  499. catch (IOException ioe)
  500. {
  501. if (_log.Level > 1)
  502. {
  503. Runtime.PrintStackTrace(ioe, _log);
  504. }
  505. throw new UnknownHostException(ioe);
  506. }
  507. if (response.Received && response.ResultCode == 0)
  508. {
  509. srcHashCode = request.Addr.GetHashCode();
  510. for (int i = 0; i < response.AddressArray.Length; i++)
  511. {
  512. response.AddressArray[i].HostName.SrcHashCode = srcHashCode;
  513. }
  514. return response.AddressArray;
  515. }
  516. }
  517. throw new UnknownHostException();
  518. }
  519. internal virtual NbtAddress[] GetHosts()
  520. {
  521. try
  522. {
  523. _waitResponse = false;
  524. byte[] bAddrBytes = laddr.GetAddressBytes();
  525. for (int i = 1; i <= 254; i++)
  526. {
  527. NodeStatusRequest request;
  528. NodeStatusResponse response;
  529. byte[] addrBytes = {
  530. bAddrBytes[0],
  531. bAddrBytes[1],
  532. bAddrBytes[2],
  533. (byte)i
  534. };
  535. IPAddress addr = new IPAddress(addrBytes);
  536. //response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
  537. // (int)addr.Address, false, 0x20));
  538. response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
  539. BitConverter.ToInt32(addr.GetAddressBytes(), 0) , false, 0x20));
  540. request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x20), null));
  541. request.Addr = addr;
  542. Send(request, response, 0);
  543. }
  544. }
  545. catch (IOException ioe)
  546. {
  547. if (_log.Level > 1)
  548. {
  549. Runtime.PrintStackTrace(ioe, _log);
  550. }
  551. throw new UnknownHostException(ioe);
  552. }
  553. _autoResetWaitReceive = new AutoResetEvent(false);
  554. _thread = new Thread(this);
  555. _thread.SetDaemon(true);
  556. _thread.Start();
  557. _autoResetWaitReceive.WaitOne();
  558. List<NbtAddress> result = new List<NbtAddress>();
  559. foreach (var key in _responseTable.Keys)
  560. {
  561. NodeStatusResponse resp = (NodeStatusResponse)_responseTable[key];
  562. if (resp.Received && resp.ResultCode == 0)
  563. {
  564. foreach (var entry in resp.AddressArray)
  565. {
  566. if (entry.HostName.HexCode == 0x20)
  567. {
  568. result.Add(entry);
  569. }
  570. }
  571. }
  572. }
  573. _responseTable.Clear();
  574. _waitResponse = true;
  575. return result.Count > 0 ? result.ToArray() : null;
  576. }
  577. }
  578. }