/InTheHand.Net.Personal/InTheHand.Net.Personal/Net.Sockets/BluetoothClient.cs

# · C# · 952 lines · 411 code · 62 blank · 479 comment · 47 complexity · f5fc22f3d59783d10195421a477f4d4c MD5 · raw file

  1. // 32feet.NET - Personal Area Networking for .NET
  2. //
  3. // InTheHand.Net.Sockets.BluetoothClient
  4. //
  5. // Copyright (c) 2003-2008 In The Hand Ltd, All rights reserved.
  6. // This source code is licensed under the In The Hand Community License - see License.txt
  7. using System;
  8. using System.Collections;
  9. using System.IO;
  10. using System.Net;
  11. using System.Net.Sockets;
  12. using System.Runtime.InteropServices;
  13. using InTheHand.Net.Bluetooth;
  14. using Microsoft.Win32;
  15. using System.Diagnostics;
  16. using InTheHand.Net.Bluetooth.Factory;
  17. #if !V1
  18. using List_IBluetoothDeviceInfo = System.Collections.Generic.List<InTheHand.Net.Bluetooth.Factory.IBluetoothDeviceInfo>;
  19. using System.Diagnostics.CodeAnalysis;
  20. #else
  21. using List_IBluetoothDeviceInfo = System.Collections.ArrayList;
  22. #endif
  23. namespace InTheHand.Net.Sockets
  24. {
  25. /// <summary>
  26. /// Provides client connections for Bluetooth RFCOMM network services.
  27. /// </summary>
  28. /// <remarks>
  29. /// <note>This class currently only supports devices which use the Microsoft
  30. /// and Widcomm Bluetooth stacks, devices which use the other stacks will
  31. /// not work.
  32. /// </note>
  33. /// <!--This para is in both the class remarks and in Connect(BtEndPoint)-->
  34. /// <para>When connecting
  35. /// normally an endpoint with an Address and a Service Class Id
  36. /// is specified, then the system will automatically lookup the SDP
  37. /// record on the remote device for that service class and connect to
  38. /// the port number (RFCOMM Channel Number) specified there.
  39. /// If instead a port value is provided in the endpoint then the SDP
  40. /// lookup will be skipped and the system will connect to the specified
  41. /// port directly.
  42. /// </para>
  43. /// <para>Note: Do not attempt to connect with service
  44. /// <see cref="F:InTheHand.Net.Bluetooth.BluetoothService.RFCommProtocol">BluetoothService.RFCommProtocol</see>
  45. /// this class always uses RFCOMM, instead the Service Class Id of the
  46. /// particular service to which you want to connect must be specified,
  47. /// perhaps
  48. /// <see cref="F:InTheHand.Net.Bluetooth.BluetoothService.SerialPort">BluetoothService.SerialPort</see>,
  49. /// <see cref="F:InTheHand.Net.Bluetooth.BluetoothService.ObexObjectPush">BluetoothService.ObexObjectPush</see>,
  50. /// or the unique UUID/<see cref="T:System.Guid"/> that you are using in
  51. /// your custom server application.
  52. /// </para>
  53. /// </remarks>
  54. [System.Diagnostics.DebuggerDisplay("impl={m_impl}")]
  55. public class BluetoothClient : IDisposable
  56. {
  57. readonly IBluetoothClient m_impl;
  58. #if TEST_EARLY && ! V1
  59. [Obsolete("(need to remove this one)")]
  60. public ISdpDiscoveryRecordsBuffer WidcommHack__GetServiceRecordsUnparsed(BluetoothAddress address, Guid serviceGuid)
  61. {
  62. WidcommBtInterface btIf = ((WidcommBluetoothClient)m_impl).m_btIf___HACK;
  63. IAsyncResult ar = btIf.BeginServiceDiscovery(address, serviceGuid, null, null);
  64. ISdpDiscoveryRecordsBuffer recs = btIf.EndServiceDiscovery(ar);
  65. return recs;
  66. }
  67. [Obsolete("(need to remove this one)")]
  68. public BOND_RETURN_CODE WidcommHack__SetPinX(BluetoothAddress address, string pin)
  69. {
  70. return ((WidcommBluetoothSecurity)WidcommBluetoothFactory.Factory.GetBluetoothSecurity()).Bond_(address, pin);
  71. }
  72. #endif
  73. #region Constructor
  74. #if NETCF
  75. static BluetoothClient()
  76. {
  77. InTheHand.Net.PlatformVerification.ThrowException();
  78. }
  79. #endif
  80. internal BluetoothClient(IBluetoothClient impl)
  81. {
  82. m_impl = impl;
  83. }
  84. /// <summary>
  85. /// Creates a new instance of <see cref="BluetoothClient"/>.
  86. /// </summary>
  87. public BluetoothClient()
  88. : this(BluetoothFactory.Factory)
  89. {
  90. }
  91. internal BluetoothClient(BluetoothFactory factory)
  92. : this(factory.DoGetBluetoothClient())
  93. {
  94. }
  95. /// <summary>
  96. /// Initializes a new instance of the <see cref="BluetoothClient"/> class and binds it to the specified local endpoint.
  97. /// </summary>
  98. /// <param name="localEP">The <see cref="BluetoothEndPoint"/> to which you bind the Bluetooth Socket.
  99. /// Only necessary on multi-radio system where you want to select the local radio to use.</param>
  100. public BluetoothClient(BluetoothEndPoint localEP)
  101. : this(BluetoothFactory.Factory, localEP)
  102. {
  103. }
  104. internal BluetoothClient(BluetoothFactory factory, BluetoothEndPoint localEP)
  105. : this(factory.DoGetBluetoothClient(localEP))
  106. {
  107. }
  108. #endregion
  109. #region InquiryAccessCode
  110. /// <summary>
  111. /// Get or set the Device Discovery Inquiry Access Code.
  112. /// </summary>
  113. /// -
  114. /// <remarks>
  115. /// <para>This is supported only the Microsoft stack on WindowsMobile/etc.
  116. /// It is not supported on any other platforms.
  117. /// </para>
  118. /// <para>The default value is
  119. /// <see cref="F:InTheHand.Net.BluetoothAddress.Giac">GIAC</see> (0x9E8B33).
  120. /// See also constant
  121. /// <see cref="F:InTheHand.Net.BluetoothAddress.Liac">LIAC</see> (0x9E8B00).
  122. /// The valid range is 0x9E8B00 through 0x9E8B3f.
  123. /// </para>
  124. /// </remarks>
  125. /// -
  126. /// <value>An <see cref="T:System.Int32"/> containing the Access Code
  127. /// to be used for Inquiry.
  128. /// </value>
  129. public int InquiryAccessCode
  130. {
  131. [DebuggerStepThrough]
  132. get { return m_impl.InquiryAccessCode; }
  133. [DebuggerStepThrough]
  134. set { m_impl.InquiryAccessCode = value; }
  135. }
  136. #endregion
  137. #region Query Length
  138. /// <summary>
  139. /// Amount of time allowed to perform the query.
  140. /// </summary>
  141. /// <remarks>On Windows CE the actual value used is expressed in units of 1.28 seconds, so will be the nearest match for the value supplied.
  142. /// The default value is 10 seconds. The maximum is 60 seconds.</remarks>
  143. public TimeSpan InquiryLength
  144. {
  145. [DebuggerStepThrough]
  146. get { return m_impl.InquiryLength; }
  147. [DebuggerStepThrough]
  148. set { m_impl.InquiryLength = value; }
  149. }
  150. #endregion
  151. #region Discover Devices
  152. /// <summary>
  153. /// Discovers accessible Bluetooth devices, both remembered and in-range,
  154. /// and returns their names and addresses.
  155. /// </summary>
  156. /// -
  157. /// <remarks>
  158. /// <para>This is equivalent to calling
  159. /// <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"
  160. /// />(255, true, true, true)
  161. /// </para>
  162. /// </remarks>
  163. /// -
  164. /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
  165. public BluetoothDeviceInfo[] DiscoverDevices()
  166. {
  167. return DiscoverDevices(255, true, true, true);
  168. }
  169. /// <summary>
  170. /// Discovers accessible Bluetooth devices, both remembered and in-range,
  171. /// and returns their names and addresses.
  172. /// </summary>
  173. /// -
  174. /// <remarks>
  175. /// <para>This is equivalent to calling
  176. /// <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"
  177. /// />(maxDevices, true, true, true)
  178. /// </para>
  179. /// </remarks>
  180. /// -
  181. /// <param name="maxDevices">The number of in-range devices to find before the inquiry may be stopped early.
  182. /// The result can contain more than this number of devices.
  183. /// </param>
  184. /// -
  185. /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
  186. public BluetoothDeviceInfo[] DiscoverDevices(int maxDevices)
  187. {
  188. return DiscoverDevices(maxDevices, true, true, true);
  189. }
  190. /// <summary>
  191. /// Discovers accessible Bluetooth devices, optionally remembered and in-range,
  192. /// and returns their names and addresses.
  193. /// </summary>
  194. /// -
  195. /// <param name="maxDevices">The number of in-range devices to find before the inquiry may be stopped early.
  196. /// The result can contain more than this number of devices.
  197. /// </param>
  198. /// <param name="authenticated">True to return previously authenticated/paired devices.</param>
  199. /// <param name="remembered">True to return remembered devices.</param>
  200. /// <param name="unknown">True to return previously unknown devices.</param>
  201. /// -
  202. /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
  203. public BluetoothDeviceInfo[] DiscoverDevices(int maxDevices, bool authenticated, bool remembered, bool unknown)
  204. {
  205. return BluetoothDeviceInfo.Wrap(m_impl.DiscoverDevices(maxDevices, authenticated, remembered, unknown, false));
  206. }
  207. /// <summary>
  208. /// Discovers accessible Bluetooth devices, optionally remembered and in-range or just in-range,
  209. /// and returns their names and addresses.
  210. /// </summary>
  211. /// -
  212. /// <remarks>
  213. /// <para>The <paramref name="discoverableOnly"/> parameter is not supported
  214. /// on the Microsoft stack on WinXP as the stack there returns the remembered and Device-Inquiry-results already
  215. /// merged, it is however supported on Windows 7.
  216. /// It is supported on WM/CE and on Widcomm (both platforms).
  217. /// Note when that flag is set the other related flag values are ignored.
  218. /// </para>
  219. /// <para>To remove devices from the list of remembered/authenticated
  220. /// devices use <see cref="M:InTheHand.Net.Bluetooth.BluetoothSecurity.RemoveDevice(InTheHand.Net.BluetoothAddress)">BluetoothSecurity.RemoveDevice</see>
  221. /// </para>
  222. /// </remarks>
  223. /// -
  224. /// <param name="maxDevices">The number of in-range devices to find before the inquiry may be stopped early.
  225. /// The result can contain more than this number of devices.
  226. /// </param>
  227. /// <param name="authenticated">True to return previously authenticated/paired devices.</param>
  228. /// <param name="remembered">True to return remembered devices.</param>
  229. /// <param name="unknown">True to return previously unknown devices.</param>
  230. /// <param name="discoverableOnly">True to return only the devices that
  231. /// are in range, and in discoverable mode. See the remarks section.</param>
  232. /// -
  233. /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
  234. [DebuggerStepThrough]
  235. public BluetoothDeviceInfo[] DiscoverDevices(int maxDevices,
  236. bool authenticated, bool remembered, bool unknown, bool discoverableOnly)
  237. {
  238. return BluetoothDeviceInfo.Wrap(m_impl.DiscoverDevices(maxDevices, authenticated, remembered, unknown, discoverableOnly));
  239. }
  240. /// <summary>
  241. /// Discovers Bluetooth devices that are in range and are in &#x2018;discoverable mode&#x2019;
  242. /// </summary>
  243. /// -
  244. /// <remarks>
  245. /// <para>This is equivalent to calling
  246. /// <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"
  247. /// />(255, false, false, false, true)
  248. /// </para>
  249. /// </remarks>
  250. /// -
  251. /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
  252. public BluetoothDeviceInfo[] DiscoverDevicesInRange()
  253. {
  254. return DiscoverDevices(255, false, false, false, true);
  255. }
  256. /// <summary>
  257. /// An asynchronous version of <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>
  258. /// </summary>
  259. /// -
  260. /// <param name="maxDevices">See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  261. /// </param>
  262. /// <param name="authenticated">See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  263. /// </param>
  264. /// <param name="remembered">See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  265. /// </param>
  266. /// <param name="unknown">See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  267. /// </param>
  268. /// <param name="discoverableOnly">See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  269. /// </param>
  270. /// <param name="callback">An optional asynchronous callback, to be called
  271. /// when the discovery is complete.
  272. /// </param>
  273. /// <param name="state">A user-provided object that distinguishes this
  274. /// particular asynchronous discovery request from other requests.
  275. /// </param>
  276. /// -
  277. /// <returns>An <see cref="T:System.IAsyncResult"/> that represents the
  278. /// asynchronous discovery, which could still be pending.
  279. /// </returns>
  280. [DebuggerStepThrough]
  281. public IAsyncResult BeginDiscoverDevices(int maxDevices,
  282. bool authenticated, bool remembered, bool unknown, bool discoverableOnly,
  283. AsyncCallback callback, object state)
  284. {
  285. #if !V1
  286. return m_impl.BeginDiscoverDevices(
  287. maxDevices, authenticated, remembered, unknown, discoverableOnly,
  288. callback, state);
  289. #else
  290. throw new NotSupportedException();
  291. #endif
  292. }
  293. /// <summary>
  294. /// Ends an asynchronous Service Record lookup query.
  295. /// </summary>
  296. /// -
  297. /// <param name="asyncResult">An <see cref="T:System.IAsyncResult"/> returned
  298. /// by <see cref="M:InTheHand.Net.Sockets.BluetoothClient.BeginDiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean,System.AsyncCallback,System.Object)"/>.
  299. /// </param>
  300. /// -
  301. /// <returns>See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean)"/>.
  302. /// </returns>
  303. public BluetoothDeviceInfo[] EndDiscoverDevices(IAsyncResult asyncResult)
  304. {
  305. #if !V1
  306. return BluetoothDeviceInfo.Wrap(m_impl.EndDiscoverDevices(asyncResult));
  307. #else
  308. throw new NotSupportedException();
  309. #endif
  310. }
  311. //--------
  312. /// <exclude/>
  313. public delegate void LiveDiscoveryCallback(IBluetoothDeviceInfo p1, object p2);
  314. internal IAsyncResult BeginDiscoverDevices(int maxDevices,
  315. bool authenticated, bool remembered, bool unknown, bool discoverableOnly,
  316. AsyncCallback callback, object state,
  317. LiveDiscoveryCallback handler, object liveDiscoState)
  318. {
  319. return m_impl.BeginDiscoverDevices(
  320. maxDevices, authenticated, remembered, unknown, discoverableOnly,
  321. callback, state,
  322. handler, liveDiscoState);
  323. }
  324. #endregion
  325. #region Available
  326. /// <summary>
  327. /// Gets the amount of data that has been received from the network and is available to be read.
  328. /// </summary>
  329. /// <value>The number of bytes of data received from the network and available to be read.</value>
  330. /// <exception cref="T:System.ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
  331. public int Available
  332. {
  333. [DebuggerStepThrough]
  334. get { return m_impl.Available; }
  335. }
  336. #endregion
  337. #region Client
  338. /// <summary>
  339. /// Gets or sets the underlying <see cref="Socket"/>.
  340. /// </summary>
  341. /// -
  342. /// <value>The underlying network <see cref="Socket"/>.</value>
  343. /// -
  344. /// <remarks>
  345. /// <note>The property is only supported on Microsoft Bluetooth stack platforms.
  346. /// </note>
  347. /// </remarks>
  348. public Socket Client
  349. {
  350. [DebuggerStepThrough]
  351. get { return m_impl.Client; }
  352. [DebuggerStepThrough]
  353. set { m_impl.Client = value; }
  354. }
  355. #endregion
  356. #region Connect
  357. /// <summary>
  358. /// Connects a client to a specified endpoint.
  359. /// </summary>
  360. /// -
  361. /// <param name="remoteEP">A <see cref="BluetoothEndPoint"/> that represents the server on the remote device.</param>
  362. /// -
  363. /// <remarks>
  364. /// <!--This para is in both the class remarks and in Connect(BtEndPoint)-->
  365. /// <para>Normally an endpoint with an Address and a Service Class Id
  366. /// is specified, then the system will automatically lookup the SDP
  367. /// record on the remote device for that service class and connect to
  368. /// the port number (RFCOMM Channel Number) specified there.
  369. /// If instead a port value is provided in the endpoint then the SDP
  370. /// lookup will be skipped and the system will connect to the specified
  371. /// port directly.
  372. /// </para>
  373. /// <para>Note: Do not attempt to connect with service
  374. /// <see cref="F:InTheHand.Net.Bluetooth.BluetoothService.RFCommProtocol">BluetoothService.RFCommProtocol</see>.
  375. /// See the <see cref="T:InTheHand.Net.Sockets.BluetoothClient">class</see> remarks for more information.
  376. /// </para>
  377. /// </remarks>
  378. public void Connect(BluetoothEndPoint remoteEP)
  379. {
  380. if (remoteEP == null) {
  381. throw new ArgumentNullException("remoteEP");
  382. }
  383. m_impl.Connect(remoteEP);
  384. }
  385. /// <summary>
  386. /// Connects the client to a remote Bluetooth host using the specified Bluetooth address and service identifier.
  387. /// </summary>
  388. /// -
  389. /// <remarks>
  390. /// <!--This para is in both the class remarks and in Connect(BtEndPoint)-->
  391. /// <para>The system will automatically lookup the SDP
  392. /// record on the remote device for that service class and connect to
  393. /// the port number (RFCOMM Channel Number) specified there.
  394. /// </para>
  395. /// <para>Note: Do not attempt to connect with service
  396. /// <see cref="F:InTheHand.Net.Bluetooth.BluetoothService.RFCommProtocol">BluetoothService.RFCommProtocol</see>.
  397. /// See the <see cref="T:InTheHand.Net.Sockets.BluetoothClient">class</see> remarks for more information.
  398. /// </para>
  399. /// </remarks>
  400. /// -
  401. /// <param name="address">The <see cref="BluetoothAddress"/> of the remote host.
  402. /// </param>
  403. /// <param name="service">The Service Class Id of the service on the remote host.
  404. /// The standard Bluetooth Service Classes are provided on class
  405. /// <see cref="T:InTheHand.Net.Bluetooth.BluetoothService"/>.
  406. /// </param>
  407. public void Connect(BluetoothAddress address, Guid service)
  408. {
  409. if (address == null) {
  410. throw new ArgumentNullException("address");
  411. }
  412. if (service == Guid.Empty) {
  413. throw new ArgumentNullException("service");
  414. }
  415. BluetoothEndPoint point = new BluetoothEndPoint(address, service);
  416. this.Connect(point);
  417. }
  418. #region Begin Connect
  419. /// <summary>
  420. /// Begins an asynchronous request for a remote host connection.
  421. /// The remote host is specified by a <see cref="BluetoothAddress"/> and a service identifier (Guid).
  422. /// </summary>
  423. /// -
  424. /// <remarks>
  425. /// <para>See the <see cref="M:InTheHand.Net.Sockets.BluetoothClient.Connect(InTheHand.Net.BluetoothAddress,System.Guid)"/>
  426. /// method for information on the usage of the values in the endpoint.
  427. /// </para>
  428. /// </remarks>
  429. /// -
  430. /// <param name="address">The <see cref="BluetoothAddress"/> of the remote host.
  431. /// </param>
  432. /// <param name="service">The Service Class Id of the service on the remote host.
  433. /// The standard Bluetooth Service Classes are provided on class
  434. /// <see cref="T:InTheHand.Net.Bluetooth.BluetoothService"/>
  435. /// </param>
  436. /// <param name="requestCallback">An <see cref="T:System.AsyncCallback"/> delegate that
  437. /// references the method to invoke when the operation is complete.
  438. /// </param>
  439. /// <param name="state">A user-defined object that contains information
  440. /// about the connect operation. This object is passed to the <paramref name="requestCallback"/>
  441. /// delegate when the operation is complete.
  442. /// </param>
  443. /// -
  444. /// <returns>An <see cref="T:System.IAsyncResult"/> that represents the
  445. /// asynchronous connect, which could still be pending.
  446. /// </returns>
  447. public IAsyncResult BeginConnect(BluetoothAddress address, Guid service, AsyncCallback requestCallback, object state)
  448. {
  449. if (address == null) {
  450. throw new ArgumentNullException("address");
  451. }
  452. if (service == Guid.Empty) {
  453. throw new ArgumentNullException("service");
  454. }
  455. return BeginConnect(new BluetoothEndPoint(address, service), requestCallback, state);
  456. }
  457. /// <summary>
  458. /// Begins an asynchronous request for a remote host connection.
  459. /// The remote server is specified by a <see cref="BluetoothEndPoint"/>.
  460. /// </summary>
  461. /// -
  462. /// <param name="remoteEP">A <see cref="BluetoothEndPoint"/> that
  463. /// represents the server on the remote device.
  464. /// See the <see cref="M:InTheHand.Net.Sockets.BluetoothClient.Connect(InTheHand.Net.BluetoothEndPoint)"/>
  465. /// method for information on the usage of the values in the endpoint.
  466. /// </param>
  467. /// <param name="requestCallback">An <see cref="T:System.AsyncCallback"/> delegate that
  468. /// references the method to invoke when the operation is complete.
  469. /// </param>
  470. /// <param name="state">A user-defined object that contains information
  471. /// about the connect operation. This object is passed to the <paramref name="requestCallback"/>
  472. /// delegate when the operation is complete.
  473. /// </param>
  474. /// -
  475. /// <remarks>
  476. /// <para>See the <see cref="M:InTheHand.Net.Sockets.BluetoothClient.Connect(InTheHand.Net.BluetoothEndPoint)"/>
  477. /// method for information on the usage of the values in the endpoint.
  478. /// </para>
  479. /// </remarks>
  480. /// -
  481. /// <returns>An <see cref="T:System.IAsyncResult"/> that represents the
  482. /// asynchronous connect, which could still be pending.
  483. /// </returns>
  484. public IAsyncResult BeginConnect(BluetoothEndPoint remoteEP, AsyncCallback requestCallback, object state)
  485. {
  486. if (remoteEP == null) {
  487. throw new ArgumentNullException("remoteEP");
  488. }
  489. return m_impl.BeginConnect(remoteEP, requestCallback, state);
  490. }
  491. #endregion
  492. #region End Connect
  493. /// <summary>
  494. /// Asynchronously accepts an incoming connection attempt.
  495. /// </summary>
  496. /// <param name="asyncResult">An <see cref="IAsyncResult"/> object returned by a call to
  497. /// <see cref="M:InTheHand.Net.Sockets.BluetoothClient.BeginConnect(InTheHand.Net.BluetoothEndPoint,System.AsyncCallback,System.Object)"/>
  498. /// / <see cref="M:InTheHand.Net.Sockets.BluetoothClient.BeginConnect(InTheHand.Net.BluetoothAddress,System.Guid,System.AsyncCallback,System.Object)"/>.
  499. /// </param>
  500. [DebuggerStepThrough]
  501. public void EndConnect(IAsyncResult asyncResult)
  502. {
  503. m_impl.EndConnect(asyncResult);
  504. }
  505. #if FX4
  506. public System.Threading.Tasks.Task ConnectAsync(BluetoothEndPoint remoteEP, object state)
  507. {
  508. return System.Threading.Tasks.Task.Factory.FromAsync(
  509. BeginConnect, EndConnect,
  510. remoteEP, state);
  511. }
  512. #endif
  513. #endregion
  514. #endregion
  515. #region Connected
  516. /// <summary>
  517. /// Gets a value indicating whether the underlying <see cref="Socket"/> for a <see cref="BluetoothClient"/> is connected to a remote host.
  518. /// </summary>
  519. /// <value>true if the <see cref="Client"/> socket was connected to a remote resource as of the most recent operation; otherwise, false.</value>
  520. public bool Connected
  521. {
  522. [DebuggerStepThrough]
  523. get { return m_impl.Connected; }
  524. }
  525. #endregion
  526. #region Close
  527. /// <summary>
  528. /// Closes the <see cref="BluetoothClient"/> and the underlying connection.
  529. /// </summary>
  530. /// -
  531. /// <remarks>The two XxxxxClient classes produced by Microsoft (TcpClient,
  532. /// and IrDAClient in the NETCF) have had various documented behaviours and various
  533. /// actual behaviours for close/dispose/finalize on the various platforms. :-(
  534. /// The current TcpClient implementation on is that
  535. /// Close/Dispose closes the connection by closing the underlying socket and/or
  536. /// NetworkStream, and finalization doesn't close either. This is the behaviour
  537. /// we use for the here (for <see cref="T:InTheHand.Net.Sockets.BluetoothClient"/>,
  538. /// <see cref="T:InTheHand.Net.Sockets.IrDAClient"/>). (The documentation in MSDN for
  539. /// <see cref="T:System.Net.Sockets.TcpClient"/> is still wrong by-the-way,
  540. /// see <see href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=158480">
  541. /// Microsoft feedback #158480</see>).
  542. /// </remarks>
  543. [DebuggerStepThrough]
  544. public void Close()
  545. {
  546. Dispose();
  547. }
  548. #endregion
  549. #region Get Stream
  550. /// <summary>
  551. /// Gets the underlying stream of data.
  552. /// </summary>
  553. /// <returns>The underlying <see cref="NetworkStream"/>.</returns>
  554. /// <remarks><see cref="GetStream"/> returns a <see cref="NetworkStream"/> that you can use to send and receive data.
  555. /// The <see cref="NetworkStream"/> class inherits from the <see cref="Stream"/> class, which provides a rich collection of methods and properties used to facilitate network communications.
  556. /// <para>You must call the <see cref="Connect(InTheHand.Net.BluetoothEndPoint)"/> / <see cref="M:InTheHand.Net.Sockets.BluetoothClient.Connect(InTheHand.Net.BluetoothAddress,System.Guid)"/>
  557. /// method first, or the <see cref="GetStream"/> method will throw an <see cref="T:System.InvalidOperationException"/>.
  558. /// After you have obtained the <see cref="NetworkStream"/>, call the <see cref="NetworkStream.Write"/> method to send data to the remote host.
  559. /// Call the <see cref="NetworkStream.Read"/> method to receive data arriving from the remote host.
  560. /// Both of these methods block until the specified operation is performed.
  561. /// You can avoid blocking on a read operation by checking the <see cref="NetworkStream.DataAvailable"/> property.
  562. /// A true value means that data has arrived from the remote host and is available for reading.
  563. /// In this case, <see cref="NetworkStream.Read"/> is guaranteed to complete immediately.
  564. /// If the remote host has shutdown its connection, <see cref="NetworkStream.Read"/> will immediately return with zero bytes.</para></remarks>
  565. /// <exception cref="T:System.InvalidOperationException">The <see cref="BluetoothClient"/> is not connected to a remote host.</exception>
  566. /// <exception cref="T:System.ObjectDisposedException">The <see cref="BluetoothClient"/> has been closed.</exception>
  567. [DebuggerStepThrough]
  568. [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  569. public NetworkStream GetStream()
  570. {
  571. return m_impl.GetStream();
  572. }
  573. #if TEST_EARLY
  574. [Obsolete("Now that we've wrapped NetworkStream there's no need for this property.")]
  575. public Stream GetStream2()
  576. {
  577. return m_impl.GetStream2();
  578. }
  579. #endif
  580. #endregion
  581. #region LingerState
  582. /// <summary>
  583. /// Gets or sets a value that specifies whether the client will delay closing
  584. /// in an attempt to send all pending data.
  585. /// </summary>
  586. /// -
  587. /// <remarks>
  588. /// <para>See <see cref="P:System.Net.Sockets.Socket.LingerState">Socket.LingerState</see>.
  589. /// </para>
  590. /// <para>In Widcomm, linger <c>false</c> (disabled) is not supported.
  591. /// </para>
  592. /// </remarks>
  593. /// -
  594. /// <value>A <see cref="T:System.Net.Sockets.LingerOption"/> that specifies
  595. /// how to linger while closing a socket.
  596. /// </value>
  597. public System.Net.Sockets.LingerOption LingerState
  598. {
  599. [DebuggerStepThrough]
  600. get { return m_impl.LingerState; }
  601. [DebuggerStepThrough]
  602. set { m_impl.LingerState = value; }
  603. }
  604. #endregion
  605. #region Authenticate
  606. /// <summary>
  607. /// Sets whether an authenticated connection is required.
  608. /// </summary>
  609. /// <remarks>
  610. /// <para>Supported mostly on the Microsoft stack (desktop and WM/CE).
  611. /// </para>
  612. /// For disconnected sockets, specifies that authentication is required in order for a connect or accept operation to complete successfully.
  613. /// Setting this option actively initiates authentication during connection establishment, if the two Bluetooth devices were not previously authenticated.
  614. /// The user interface for passkey exchange, if necessary, is provided by the operating system outside the application context.
  615. /// For outgoing connections that require authentication, the connect operation fails (on Win32, with WSAEACCES) if authentication is not successful.
  616. /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
  617. /// For incoming connections, the connection is rejected if authentication cannot be established and fails (on Win32, returning a WSAEHOSTDOWN error).
  618. /// <para>MSDN. Desktop: <see href="http://msdn.microsoft.com/en-us/library/aa362911(VS.85).aspx" />
  619. /// , WM: <see href="http://msdn.microsoft.com/en-us/library/aa915899.aspx" />
  620. /// </para>
  621. /// </remarks>
  622. public bool Authenticate
  623. {
  624. get { return m_impl.Authenticate; }
  625. set { m_impl.Authenticate = value; }
  626. }
  627. #endregion
  628. #region Encrypt
  629. /// <summary>
  630. /// Sets whether an encrypted connection is required.
  631. /// </summary>
  632. /// -
  633. /// <remarks>
  634. /// <para>Supported mostly on the Microsoft stack (desktop and WM/CE).
  635. /// </para>
  636. /// On unconnected sockets, enforces encryption to establish a connection.
  637. /// Encryption is only available for authenticated connections.
  638. /// For incoming connections, a connection for which encryption cannot be established is automatically rejected (and on Win32, returns WSAEHOSTDOWN as the error).
  639. /// For outgoing connections, the Connect function fails (on Win32, with WSAEACCES) if encryption cannot be established.
  640. /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
  641. /// <note>For Windows Mobile/CE:
  642. /// On a connected socket, this command will toggle encryption for all sessions sharing the same Baseband connection. You should use it ONLY if you know what you are doing (for example, yours is the only application); otherwise, the link presumed more secure by another application may become unencrypted.
  643. /// </note>
  644. /// <para>MSDN. Desktop: <see href="http://msdn.microsoft.com/en-us/library/aa362911(VS.85).aspx" />
  645. /// , WM: <see href="http://msdn.microsoft.com/en-us/library/aa915899.aspx" />
  646. /// </para>
  647. /// </remarks>
  648. public bool Encrypt
  649. {
  650. [DebuggerStepThrough]
  651. get { return m_impl.Encrypt; }
  652. [DebuggerStepThrough]
  653. set { m_impl.Encrypt = value; }
  654. }
  655. #endregion
  656. #region Link Key
  657. /// <summary>
  658. /// Returns link key associated with peer Bluetooth device.
  659. /// </summary>
  660. public Guid LinkKey
  661. {
  662. [DebuggerStepThrough]
  663. get { return m_impl.LinkKey; }
  664. }
  665. #endregion
  666. #region Link Policy
  667. /// <summary>
  668. /// Returns the Link Policy of the current connection.
  669. /// </summary>
  670. public LinkPolicy LinkPolicy
  671. {
  672. get { return m_impl.LinkPolicy; }
  673. }
  674. #endregion
  675. #region Set PIN
  676. /// <summary>
  677. /// Sets the PIN associated with the remote device.
  678. /// </summary>
  679. /// <param name="pin">PIN which must be composed of 1 to 16 ASCII characters.</param>
  680. /// <remarks>
  681. /// <para>Is not supported on all platforms.
  682. /// For instance see the Widcomm documentation
  683. /// </para>
  684. /// <para>Assigning null (Nothing in VB) or an empty String will revoke the PIN.
  685. /// </para>
  686. /// <para>In version 2.3 could only be called when connected.
  687. /// </para>
  688. /// </remarks>
  689. [DebuggerStepThrough]
  690. public void SetPin(string pin)
  691. {
  692. m_impl.SetPin(pin);
  693. }
  694. /// <summary>
  695. /// Set or change the PIN to be used with a specific remote device.
  696. /// </summary>
  697. /// <param name="device">Address of Bluetooth device.</param>
  698. /// <param name="pin">PIN string consisting of 1 to 16 ASCII characters.</param>
  699. /// <remarks>
  700. /// <para>Is not supported on all platforms.
  701. /// For instance see the Widcomm documentation
  702. /// </para>
  703. /// <para>Assigning null (Nothing in VB) or an empty String will revoke the PIN.
  704. /// </para>
  705. /// </remarks>
  706. [DebuggerStepThrough]
  707. public void SetPin(BluetoothAddress device, string pin)
  708. {
  709. m_impl.SetPin(device, pin);
  710. }
  711. #endregion
  712. #region Remote Machine Name
  713. /// <summary>
  714. /// Get the remote endpoint.
  715. /// </summary>
  716. /// -
  717. /// <value>
  718. /// The <see cref="T:InTheHand.Net.BluetoothEndPoint"/> with which the
  719. /// <see cref="T:InTheHand.Net.Sockets.BluetoothClient"/> is communicating.
  720. /// </value>
  721. /// -
  722. /// <remarks>
  723. /// <para>Note it can't be guaranteed that the <see cref="P:InTheHand.Net.BluetoothEndPoint.Service"/>
  724. /// and <see cref="P:InTheHand.Net.BluetoothEndPoint.Port"/> parts
  725. /// of the returned endpoint are valid; and this will affect the
  726. /// <see cref="M:InTheHand.Net.BluetoothEndPoint.ToString"/> output.
  727. /// In particular, on MSFT, the <see cref="P:InTheHand.Net.Sockets.BluetoothClient.RemoteEndPoint"/>
  728. /// for a client connection seems to have no <see cref="P:InTheHand.Net.BluetoothEndPoint.Port"/>
  729. /// and a garbage <see cref="P:InTheHand.Net.BluetoothEndPoint.Service"/>,
  730. /// so we would display garbage there in <see cref="M:InTheHand.Net.BluetoothEndPoint.ToString"/>.
  731. /// An in-bound/server connection however does have a valid Port.
  732. /// (There the endpoints are returned from the native socket).
  733. /// On the other hand on Widcomm, Bluetopia and on BlueSoleil the
  734. /// opposite is the case: for a client the Port is known but it isn't
  735. /// for a server, and the <see cref="P:InTheHand.Net.BluetoothEndPoint.Service"/>
  736. /// is blank in both cases.
  737. /// </para>
  738. /// </remarks>
  739. public BluetoothEndPoint RemoteEndPoint
  740. {
  741. [DebuggerStepThrough]
  742. get { return m_impl.RemoteEndPoint; }
  743. }
  744. /// <summary>
  745. /// Gets the name of the remote device.
  746. /// </summary>
  747. public string RemoteMachineName
  748. {
  749. [DebuggerStepThrough]
  750. get { return m_impl.RemoteMachineName; }
  751. }
  752. /// <summary>
  753. /// Gets the name of the specified remote device.
  754. /// </summary>
  755. /// <param name="a">Address of remote device.</param>
  756. /// <returns>Friendly name of specified device.</returns>
  757. [DebuggerStepThrough]
  758. public string GetRemoteMachineName(BluetoothAddress a)
  759. {
  760. return m_impl.GetRemoteMachineName(a);
  761. }
  762. /// <summary>
  763. /// Gets the name of a device by a specified socket.
  764. /// </summary>
  765. /// <param name="s"> A <see cref="Socket"/>.</param>
  766. /// <returns>Returns a string value of the computer or device name.</returns>
  767. public static string GetRemoteMachineName(Socket s)
  768. {
  769. #if WinCE
  770. return InTheHand.Net.Bluetooth.Msft.SocketBluetoothClient.GetRemoteMachineName(s);
  771. #else
  772. var bdi = new BluetoothDeviceInfo(((BluetoothEndPoint)s.RemoteEndPoint).Address);
  773. return bdi.DeviceName;
  774. #endif
  775. }
  776. #endregion
  777. #region IDisposable Members
  778. /// <summary>
  779. /// Closes the <see cref="BluetoothClient"/> and the underlying connection.
  780. /// </summary>
  781. /// -
  782. /// <seealso cref="M:InTheHand.Net.Sockets.BluetoothClient.Close"/>
  783. [DebuggerStepThrough]
  784. public void Dispose()
  785. {
  786. m_impl.Dispose();
  787. }
  788. #endregion
  789. [Obsolete("Use the four Boolean method.")] // Is used by UnitTests
  790. internal static List_IBluetoothDeviceInfo DiscoverDevicesMerge(
  791. bool authenticated, bool remembered, bool unknown,
  792. List_IBluetoothDeviceInfo knownDevices,
  793. List_IBluetoothDeviceInfo discoverableDevices, DateTime discoTime)
  794. {
  795. return DiscoverDevicesMerge(authenticated, remembered, unknown,
  796. knownDevices, discoverableDevices,
  797. false, discoTime);
  798. }
  799. internal static List_IBluetoothDeviceInfo DiscoverDevicesMerge(
  800. bool authenticated, bool remembered, bool unknown,
  801. List_IBluetoothDeviceInfo knownDevices,
  802. List_IBluetoothDeviceInfo discoverableDevices,
  803. bool discoverableOnly, DateTime discoTime)
  804. {
  805. // Check args
  806. if (unknown || discoverableOnly) {
  807. if (discoverableDevices == null)
  808. throw new ArgumentNullException("discoverableDevices");
  809. } else {
  810. bool nunit = TestUtilities.IsUnderTestHarness(); // Don't warn then.
  811. Debug.Assert(nunit || discoverableDevices == null, "No need to run SLOW Inquiry when not wanting 'unknown'.");
  812. }
  813. if (knownDevices == null)
  814. throw new ArgumentNullException("knownDevices");
  815. AssertNoDuplicates(knownDevices, "knownDevices");
  816. AssertNoDuplicates(discoverableDevices, "discoverableDevices");
  817. //
  818. bool addFromKnown_General;
  819. if (discoverableOnly) {
  820. addFromKnown_General = false;
  821. } else {
  822. addFromKnown_General = authenticated || remembered;
  823. if (!addFromKnown_General && !unknown)
  824. return new List_IBluetoothDeviceInfo();
  825. }
  826. List_IBluetoothDeviceInfo merged;
  827. if (unknown || discoverableOnly)
  828. merged = new List_IBluetoothDeviceInfo(discoverableDevices);
  829. else
  830. merged = new List_IBluetoothDeviceInfo();
  831. //
  832. foreach (IBluetoothDeviceInfo cur in knownDevices) {
  833. bool debug_contains = false;
  834. //TODO #if DEBUG
  835. foreach (IBluetoothDeviceInfo curMerged in merged) {
  836. if (BluetoothDeviceInfo.EqualsIBDI(curMerged, cur)) {
  837. debug_contains = true;
  838. break;
  839. }
  840. }
  841. //#endif
  842. //--
  843. int idx = BluetoothDeviceInfo.ListIndexOf(merged, cur);
  844. if (idx != -1) {
  845. // The device is both in the inquiry result and the remembered list.
  846. // Does the called want "already known" devices? If so, update
  847. // to the correct flags, otherwise remove it.
  848. Debug.Assert(debug_contains);
  849. if (addFromKnown_General || discoverableOnly) {
  850. ((IBluetoothDeviceInfo)merged[idx]).Merge(cur);
  851. // (The casts are for the NETCFv1 build).
  852. } else {
  853. merged.RemoveAt(idx);
  854. }
  855. } else {
  856. // The device is not in inquiry result, do we add it from the known list?
  857. Debug.Assert(!debug_contains);
  858. bool addFromKnown_Specific
  859. = (remembered && cur.Remembered)
  860. || (authenticated && cur.Authenticated);
  861. if (addFromKnown_General && addFromKnown_Specific) {
  862. merged.Add(cur);
  863. }
  864. }
  865. }//for
  866. AssertNoDuplicates(merged, "merged");
  867. return merged;
  868. }
  869. [Conditional("DEBUG")]
  870. [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.String.Format(System.IFormatProvider,System.String,System.Object[])")]
  871. private static void AssertNoDuplicates(
  872. List_IBluetoothDeviceInfo deviceList, string location)
  873. {
  874. // (The casts are for the NETCFv1 build).
  875. if (deviceList == null)
  876. return;
  877. for (int i = 0; i < deviceList.Count; ++i) {
  878. IBluetoothDeviceInfo cur = (IBluetoothDeviceInfo)deviceList[i];
  879. BluetoothAddress curAddr = cur.DeviceAddress;
  880. for (int j = i + 1; j < deviceList.Count; ++j) {
  881. if (((IBluetoothDeviceInfo)deviceList[j]).DeviceAddress == curAddr) {
  882. string msg = string.Format(System.Globalization.CultureInfo.InvariantCulture,
  883. "'{0}' duplicate #{1}==#{2}: '{3}' '{4}'", location, i, j, cur, deviceList[j]);
  884. Debug.Fail(msg);
  885. }
  886. }
  887. }
  888. }
  889. }//class--BluetoothClient
  890. }