NameServiceClient.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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 ex)
  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. catch (Exception ex)
  249. {
  250. if (_log.Level > 2)
  251. {
  252. Runtime.PrintStackTrace(ex, _log);
  253. }
  254. }
  255. finally
  256. {
  257. TryClose();
  258. }
  259. }
  260. /// <exception cref="System.IO.IOException"></exception>
  261. internal virtual void Send(NameServicePacket request, NameServicePacket response,
  262. int timeout)
  263. {
  264. int nid = 0;
  265. int max = NbtAddress.Nbns.Length;
  266. if (max == 0)
  267. {
  268. max = 1;
  269. }
  270. lock (response)
  271. {
  272. while (max-- > 0)
  273. {
  274. try
  275. {
  276. lock (_lock)
  277. {
  278. request.NameTrnId = GetNextNameTrnId();
  279. nid = request.NameTrnId;
  280. response.Received = false;
  281. _responseTable.Put(nid, response);
  282. EnsureOpen(timeout + 1000);
  283. int requestLenght = request.WriteWireFormat(_sndBuf, 0);
  284. _socket.Send(_sndBuf, 0, requestLenght, new IPEndPoint(request.Addr, _lport));
  285. if (_log.Level > 3)
  286. {
  287. _log.WriteLine(request);
  288. Hexdump.ToHexdump(_log, _sndBuf, 0, requestLenght);
  289. }
  290. }
  291. if (_waitResponse)
  292. {
  293. long start = Runtime.CurrentTimeMillis();
  294. while (timeout > 0)
  295. {
  296. Runtime.Wait(response, timeout);
  297. if (response.Received && request.QuestionType == response.RecordType)
  298. {
  299. return;
  300. }
  301. response.Received = false;
  302. timeout -= (int)(Runtime.CurrentTimeMillis() - start);
  303. }
  304. }
  305. }
  306. catch (Exception ie)
  307. {
  308. throw new IOException(ie.Message);
  309. }
  310. finally
  311. {
  312. //Sharpen.Collections.Remove(responseTable, nid);
  313. if (_waitResponse)
  314. {
  315. _responseTable.Remove(nid);
  316. }
  317. }
  318. if (_waitResponse)
  319. {
  320. lock (_lock)
  321. {
  322. if (NbtAddress.IsWins(request.Addr) == false)
  323. {
  324. break;
  325. }
  326. if (request.Addr == NbtAddress.GetWinsAddress())
  327. {
  328. NbtAddress.SwitchWins();
  329. }
  330. request.Addr = NbtAddress.GetWinsAddress();
  331. }
  332. }
  333. }
  334. }
  335. }
  336. /// <exception cref="UnknownHostException"></exception>
  337. internal virtual NbtAddress[] GetAllByName(Name name, IPAddress addr)
  338. {
  339. int n;
  340. NameQueryRequest request = new NameQueryRequest(name);
  341. NameQueryResponse response = new NameQueryResponse();
  342. request.Addr = addr ?? NbtAddress.GetWinsAddress();
  343. request.IsBroadcast = request.Addr == null;
  344. if (request.IsBroadcast)
  345. {
  346. request.Addr = Baddr;
  347. n = RetryCount;
  348. }
  349. else
  350. {
  351. request.IsBroadcast = false;
  352. n = 1;
  353. }
  354. do
  355. {
  356. try
  357. {
  358. Send(request, response, RetryTimeout);
  359. }
  360. catch (IOException ioe)
  361. {
  362. if (_log.Level > 1)
  363. {
  364. Runtime.PrintStackTrace(ioe, _log);
  365. }
  366. throw new UnknownHostException(ioe);
  367. }
  368. if (response.Received && response.ResultCode == 0)
  369. {
  370. return response.AddrEntry;
  371. }
  372. }
  373. while (--n > 0 && request.IsBroadcast);
  374. throw new UnknownHostException();
  375. }
  376. /// <exception cref="UnknownHostException"></exception>
  377. internal virtual NbtAddress GetByName(Name name, IPAddress addr)
  378. {
  379. int n;
  380. NameQueryRequest request = new NameQueryRequest(name);
  381. NameQueryResponse response = new NameQueryResponse();
  382. if (addr != null)
  383. {
  384. request.Addr = addr;
  385. request.IsBroadcast = (addr.GetAddressBytes()[3] == unchecked(unchecked(0xFF)));
  386. n = RetryCount;
  387. do
  388. {
  389. try
  390. {
  391. Send(request, response, RetryTimeout);
  392. }
  393. catch (IOException ioe)
  394. {
  395. if (_log.Level > 1)
  396. {
  397. Runtime.PrintStackTrace(ioe, _log);
  398. }
  399. throw new UnknownHostException(ioe);
  400. }
  401. if (response.Received && response.ResultCode == 0
  402. && response.IsResponse)
  403. {
  404. int last = response.AddrEntry.Length - 1;
  405. response.AddrEntry[last].HostName.SrcHashCode = addr.GetHashCode();
  406. return response.AddrEntry[last];
  407. }
  408. }
  409. while (--n > 0 && request.IsBroadcast);
  410. throw new UnknownHostException();
  411. }
  412. for (int i = 0; i < _resolveOrder.Length; i++)
  413. {
  414. try
  415. {
  416. switch (_resolveOrder[i])
  417. {
  418. case ResolverLmhosts:
  419. {
  420. NbtAddress ans = Lmhosts.GetByName(name);
  421. if (ans != null)
  422. {
  423. ans.HostName.SrcHashCode = 0;
  424. // just has to be different
  425. // from other methods
  426. return ans;
  427. }
  428. break;
  429. }
  430. case ResolverWins:
  431. case ResolverBcast:
  432. {
  433. if (_resolveOrder[i] == ResolverWins && name.name != NbtAddress.MasterBrowserName
  434. && name.HexCode != unchecked(0x1d))
  435. {
  436. request.Addr = NbtAddress.GetWinsAddress();
  437. request.IsBroadcast = false;
  438. }
  439. else
  440. {
  441. request.Addr = Baddr;
  442. request.IsBroadcast = true;
  443. }
  444. n = RetryCount;
  445. while (n-- > 0)
  446. {
  447. try
  448. {
  449. Send(request, response, RetryTimeout);
  450. }
  451. catch (IOException ioe)
  452. {
  453. if (_log.Level > 1)
  454. {
  455. Runtime.PrintStackTrace(ioe, _log);
  456. }
  457. throw new UnknownHostException(ioe);
  458. }
  459. if (response.Received && response.ResultCode == 0
  460. && response.IsResponse)
  461. {
  462. response.AddrEntry[0].HostName.SrcHashCode = request.Addr.GetHashCode();
  463. return response.AddrEntry[0];
  464. }
  465. if (_resolveOrder[i] == ResolverWins)
  466. {
  467. break;
  468. }
  469. }
  470. break;
  471. }
  472. }
  473. }
  474. catch (IOException)
  475. {
  476. }
  477. }
  478. throw new UnknownHostException();
  479. }
  480. /// <exception cref="UnknownHostException"></exception>
  481. internal virtual NbtAddress[] GetNodeStatus(NbtAddress addr)
  482. {
  483. int n;
  484. int srcHashCode;
  485. NodeStatusRequest request;
  486. NodeStatusResponse response;
  487. response = new NodeStatusResponse(addr);
  488. request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x00), null));
  489. request.Addr = addr.GetInetAddress();
  490. n = RetryCount;
  491. while (n-- > 0)
  492. {
  493. try
  494. {
  495. Send(request, response, RetryTimeout);
  496. }
  497. catch (IOException ioe)
  498. {
  499. if (_log.Level > 1)
  500. {
  501. Runtime.PrintStackTrace(ioe, _log);
  502. }
  503. throw new UnknownHostException(ioe);
  504. }
  505. if (response.Received && response.ResultCode == 0)
  506. {
  507. srcHashCode = request.Addr.GetHashCode();
  508. for (int i = 0; i < response.AddressArray.Length; i++)
  509. {
  510. response.AddressArray[i].HostName.SrcHashCode = srcHashCode;
  511. }
  512. return response.AddressArray;
  513. }
  514. }
  515. throw new UnknownHostException();
  516. }
  517. internal virtual NbtAddress[] GetHosts()
  518. {
  519. try
  520. {
  521. _waitResponse = false;
  522. byte[] bAddrBytes = laddr.GetAddressBytes();
  523. for (int i = 1; i <= 254; i++)
  524. {
  525. NodeStatusRequest request;
  526. NodeStatusResponse response;
  527. byte[] addrBytes = {
  528. bAddrBytes[0],
  529. bAddrBytes[1],
  530. bAddrBytes[2],
  531. (byte)i
  532. };
  533. IPAddress addr = new IPAddress(addrBytes);
  534. //response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
  535. // (int)addr.Address, false, 0x20));
  536. response = new NodeStatusResponse(new NbtAddress(NbtAddress.UnknownName,
  537. BitConverter.ToInt32(addr.GetAddressBytes(), 0) , false, 0x20));
  538. request = new NodeStatusRequest(new Name(NbtAddress.AnyHostsName, unchecked(0x20), null));
  539. request.Addr = addr;
  540. Send(request, response, 0);
  541. }
  542. }
  543. catch (IOException ioe)
  544. {
  545. if (_log.Level > 1)
  546. {
  547. Runtime.PrintStackTrace(ioe, _log);
  548. }
  549. throw new UnknownHostException(ioe);
  550. }
  551. _autoResetWaitReceive = new AutoResetEvent(false);
  552. _thread = new Thread(this);
  553. _thread.SetDaemon(true);
  554. _thread.Start();
  555. _autoResetWaitReceive.WaitOne();
  556. List<NbtAddress> result = new List<NbtAddress>();
  557. foreach (var key in _responseTable.Keys)
  558. {
  559. NodeStatusResponse resp = (NodeStatusResponse)_responseTable[key];
  560. if (resp.Received && resp.ResultCode == 0)
  561. {
  562. foreach (var entry in resp.AddressArray)
  563. {
  564. if (entry.HostName.HexCode == 0x20)
  565. {
  566. result.Add(entry);
  567. }
  568. }
  569. }
  570. }
  571. _responseTable.Clear();
  572. _waitResponse = true;
  573. return result.Count > 0 ? result.ToArray() : null;
  574. }
  575. }
  576. }