SocketBluetoothClient.cs :  » Business-Application » 32feet.NET » InTheHand » Net » Sockets » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Business Application » 32feet.NET 
32feet.NET » InTheHand » Net » Sockets » SocketBluetoothClient.cs
// 32feet.NET - Personal Area Networking for .NET
//
// InTheHand.Net.Sockets.BluetoothClient
// 
// Copyright (c) 2003-2008 In The Hand Ltd, All rights reserved.
// This source code is licensed under the In The Hand Community License - see License.txt

//#define WIN32_READ_BTH_DEVICE_INFO

using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using InTheHand.Net.Bluetooth;
using Microsoft.Win32;
using InTheHand.Runtime.InteropServices;
#if !V1
using List_IBluetoothDeviceInfoSystem.Collections.Generic.ListInTheHand.Net.Bluetooth.Factory.IBluetoothDeviceInfo;
#else
using List_IBluetoothDeviceInfoSystem.Collections.ArrayList;
#endif
#if !V1
using AsyncResult_BeginDiscoverDevicesInTheHand.Net.AsyncResultInTheHand.Net.Bluetooth.Factory.IBluetoothDeviceInfoInTheHand.Net.Bluetooth.Factory.DiscoDevsParams;
using System.Diagnostics.CodeAnalysis;
#endif
using System.Diagnostics;
using InTheHand.Net.Bluetooth.Factory;

namespace InTheHand.Net.Sockets{
  /// <summary>
  /// Provides client connections for Bluetooth network services.
  /// </summary>
  /// <!-- SocketBluetoothClient --> <remarks>This class currently only supports devices which use the Microsoft Bluetooth stack, devices which use the WidComm stack will not work.</remarks>
  class SocketBluetoothClient : IBluetoothClient
  {
        private bool cleanedUp = false;
        private SocketOptionHelper m_optionHelper;
#if WinXP
        // If SetPin(String) is called before connect we need to know the remote 
        // address to start the BluetoothWin32Authenticator for, so store this 
        // so we can start the authenticator at connect-time.
        string m_pinForConnect;
#endif

    #region Constructor
#if NETCF
        static SocketBluetoothClient()
        {
            InTheHand.Net.PlatformVerification.ThrowException();
        }
#endif

    /// <summary>
        /// Creates a new instance of <see cref="BluetoothClient"/>.
    /// </summary>
    public SocketBluetoothClient()
    {
                
            try
            {
                this.Client = new Socket(AddressFamily32.Bluetooth, SocketType.Stream, BluetoothProtocolType.RFComm);
            }
            catch (SocketException se)
            {
                throw new PlatformNotSupportedException("32feet.NET does not support the Bluetooth stack on this device.", se);
            }
            m_optionHelper = new SocketOptionHelper(this.Client);
    }
        /// <summary>
        /// Initializes a new instance of the <see cref="BluetoothClient"/> class and binds it to the specified local endpoint.
        /// </summary>
        /// <param name="localEP">The <see cref="BluetoothEndPoint"/> to which you bind the Bluetooth Socket.
        /// Only necessary on multi-radio system where you want to select the local radio to use.</param>
        public SocketBluetoothClient(BluetoothEndPoint localEP)
            : this()
        {
            if (localEP == null)
            {
                throw new ArgumentNullException("localEP");
            }

            //bind to specific local endpoint
            this.Client.Bind(localEP);
        }

        internal SocketBluetoothClient(Socket acceptedSocket)
    {
            this.Client = acceptedSocket;
            active = true;
            m_optionHelper = new SocketOptionHelper(this.Client);
        }

    #endregion

        #region InquiryAccessCode
        private int iac = BluetoothAddress.Giac; //0x9E8B33;
#if NETCF
        /// <summary>
        /// 
        /// </summary>
        public int InquiryAccessCode
        {
            get
            {
                return iac;
            }
            set
            {
                iac = value;
            }
        }
#else
        public int InquiryAccessCode
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }
#endif
        #endregion

    #region Query Length

    //length of time for query
    private TimeSpan inquiryLength = new TimeSpan(0,0,10);

    /// <summary>
    /// Amount of time allowed to perform the query.
    /// </summary>
    /// <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.
    /// The default value is 10 seconds. The maximum is 60 seconds.</remarks>
    public TimeSpan InquiryLength
    {
      get
      {
        return inquiryLength;
      }
      set
      {
        if((value.TotalSeconds > 0) && (value.TotalSeconds <= 60))
        {
          inquiryLength = value;
        }
        else
        {
          throw new  ArgumentOutOfRangeException(
#if !V1
                        "value", 
#endif
                        "QueryLength must be a positive timespan between 0 and 60 seconds.");
        }
      }
    }
    #endregion

    #region Discover Devices
    /// <summary>
    /// Discovers accessible Bluetooth devices and returns their names and addresses.
    /// </summary>
    /// <param name="maxDevices">The maximum number of devices to get information about.</param>
    /// <param name="authenticated">True to return previously authenticated/paired devices.</param>
    /// <param name="remembered">True to return remembered devices.</param>
    /// <param name="unknown">True to return previously unknown devices.</param>
    /// <param name="discoverableOnly">True to return only discoverable devices
        /// (where both in range and in discoverable mode).
        /// When <see langword="true"/> all other flags are ignored.
        /// <strong>Note: Does NOT work on Win32 with the Microsoft stack.</strong>
        /// </param>
    /// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
        /// -
        /// <remarks>
        /// <para>The <see paramref="discoverableOnly"/> flag will discover only 
        /// the devices that are in range and are in discoverable mode.  This works 
        /// only on WM/CE with the Microsoft stack, or on any platform with the 
        /// Widcomm stack.
        /// </para>
        /// <para>
        /// It does not work on desktop Windows with the Microsoft 
        /// stack, where the in range and remembered devices are returned already 
        /// merged!  There simple all devices will be returned.  Even the 
        /// <see cref="InTheHand.Net.Sockets.BluetoothDeviceInfo.LastSeen">BluetoothDeviceInfo.LastSeen</see>
        /// property is of no use there: on XP and Vista at least the value provided 
        /// is always simply the current time.
        /// </para>
        /// </remarks>
    public IBluetoothDeviceInfo[] DiscoverDevices(int maxDevices,
            bool authenticated, bool remembered, bool unknown, bool discoverableOnly)
    {
            WqsOffset.AssertCheckLayout();
            CsaddrInfoOffsets.AssertCheckLayout();
            //
#if WinXP
            const bool Win32DiscoverableOnlyIncludesAllDevices = false;
#endif
      int discoveredDevices = 0;
            List_IBluetoothDeviceInfo al = null;
      
      int handle = 0;
      int lookupresult = 0;


      
#if WinXP
            if (discoverableOnly && !Win32DiscoverableOnlyIncludesAllDevices) {
                // No way to separate out the devices-in-range on Win32. :-(
                return new IBluetoothDeviceInfo[0];
            }
#endif
#if NETCF
            DateTime discoTime = DateTime.UtcNow;
            if(unknown || discoverableOnly)
            {
#endif
        al = new List_IBluetoothDeviceInfo();
        byte[] buffer = new byte[1024];
        BitConverter.GetBytes(WqsOffset.StructLength_60).CopyTo(buffer, WqsOffset.dwSize_0);
        BitConverter.GetBytes(WqsOffset.NsBth_16).CopyTo(buffer, WqsOffset.dwNameSpace_20);

        int bufferlen = buffer.Length;

        
                BTHNS_INQUIRYBLOB bib = new BTHNS_INQUIRYBLOB();
                bib.LAP = iac;// 0x9E8B33;

#if NETCF
                bib.length = Convert.ToInt16(inquiryLength.TotalSeconds / 1.28);
                bib.num_responses = Convert.ToInt16(maxDevices);
#else
                bib.length = Convert.ToByte(inquiryLength.TotalSeconds);
#endif
                GCHandle hBib = GCHandle.Alloc(bib, GCHandleType.Pinned);
                IntPtr pBib = hBib.AddrOfPinnedObject();
                
                BLOB b = new BLOB(8, pBib);

      
                GCHandle hBlob = GCHandle.Alloc(b, GCHandleType.Pinned);

                Marshal32.WriteIntPtr(buffer, WqsOffset.lpBlob_56, hBlob.AddrOfPinnedObject());
                    

        //start looking for Bluetooth devices
                LookupFlags flags = LookupFlags.Containers;

#if WinXP
                //ensure cache is cleared on XP when looking for new devices
                if(unknown || discoverableOnly)
                {
                    flags |= LookupFlags.FlushCache;
                }
#endif
                lookupresult = NativeMethods.WSALookupServiceBegin(buffer, flags, out handle);

        hBlob.Free();
                hBib.Free();

        while(discoveredDevices < maxDevices && lookupresult != -1)
        {
#if NETCF
          lookupresult = NativeMethods.WSALookupServiceNext(handle, LookupFlags.ReturnAddr | LookupFlags.ReturnBlob , ref bufferlen, buffer);
#else
                    LookupFlags flagsNext = LookupFlags.ReturnAddr;
#if WIN32_READ_BTH_DEVICE_INFO
                    flagsNext |= LookupFlags.ReturnBlob;
#endif
                    lookupresult = NativeMethods.WSALookupServiceNext(handle, flagsNext, ref bufferlen, buffer);
#endif

                    if (lookupresult != -1)
          {
            //increment found count
            discoveredDevices++;

        
            //status
#if WinXP
                        BTHNS_RESULT status = (BTHNS_RESULT)BitConverter.ToInt32(buffer, WqsOffset.dwOutputFlags_52);
                        bool devAuthd = ((status & BTHNS_RESULT.Authenticated) == BTHNS_RESULT.Authenticated);
                        bool devRembd = ((status & BTHNS_RESULT.Remembered) == BTHNS_RESULT.Remembered);
                        if (devAuthd && !devRembd) {
                            System.Diagnostics.Debug.WriteLine("Win32 BT disco: Auth'd but NOT Remembered.");
                        }
                        bool devUnkwn = !devRembd && !devAuthd;
                        bool include = (authenticated && devAuthd) || (remembered && devRembd) || (unknown && devUnkwn);
                        Debug.Assert(!discoverableOnly, "Expected short circuit for Win32 unsupported discoverableOnly!");
                        if (include)
#else
                        if(true)
#endif
                        {
#if NETCF
                            IntPtr lpBlob = (IntPtr)BitConverter.ToInt32(buffer, 56);
                            BLOB ib = (BLOB)Marshal.PtrToStructure(lpBlob, typeof(BLOB));
                            BthInquiryResult bir = (BthInquiryResult)Marshal.PtrToStructure(ib.pBlobData, typeof(BthInquiryResult));
#endif
                            //struct CSADDR_INFO {
                            //    SOCKET_ADDRESS LocalAddr;
                            //    SOCKET_ADDRESS RemoteAddr;
                            //    INT iSocketType;
                            //    INT iProtocol;
                            //}
                            //struct SOCKET_ADDRESS {
                            //    LPSOCKADDR lpSockaddr;
                            //    INT iSockaddrLength;
                            //}
              //pointer to outputbuffer
                            IntPtr bufferptr = Marshal32.ReadIntPtr(buffer, WqsOffset.lpcsaBuffer_48);
              //remote socket address
              IntPtr sockaddrptr = Marshal32.ReadIntPtr(bufferptr, CsaddrInfoOffsets.OffsetRemoteAddr_lpSockaddr_8);
              //remote socket len
              int sockaddrlen = Marshal.ReadInt32(bufferptr, CsaddrInfoOffsets.OffsetRemoteAddr_iSockaddrLength_12);
          

              SocketAddress btsa = new SocketAddress(AddressFamily32.Bluetooth, sockaddrlen);
            
              for(int sockbyte = 0; sockbyte < sockaddrlen; sockbyte++)
              {
                btsa[sockbyte] = Marshal.ReadByte(sockaddrptr, sockbyte);
              }

              BluetoothEndPoint bep = new BluetoothEndPoint(null, BluetoothService.Empty);
              bep = (BluetoothEndPoint)bep.Create(btsa);
        
              //new deviceinfo
              IBluetoothDeviceInfo newdevice;

#if NETCF
              newdevice = new WindowsBluetoothDeviceInfo(bep.Address, bir.cod);
#else
                            newdevice = new WindowsBluetoothDeviceInfo(bep.Address);
#if WIN32_READ_BTH_DEVICE_INFO
                            ReadBlobBTH_DEVICE_INFO(buffer, newdevice);
#endif
#endif
              //add to discovered list
              al.Add(newdevice);
            }


          }
        }
#if NETCF
      }
#endif

      //stop looking
            if(handle!=0)
      {
        lookupresult = NativeMethods.WSALookupServiceEnd(handle);
      }

#if NETCF
            List_IBluetoothDeviceInfo known = WinCEReadKnownDevicesFromRegistry();
            al = BluetoothClient.DiscoverDevicesMerge(authenticated, remembered, unknown,
                known, al, discoverableOnly, discoTime);
#endif


            //return results
      if(al.Count == 0)
      {
        //special case for empty collection
        return new IBluetoothDeviceInfo[0]{};
      }

            return (IBluetoothDeviceInfo[])al.ToArray(
#if V1
                typeof(IBluetoothDeviceInfo)
#endif
                );
        }

#if WinXP
        private void ReadBlobBTH_DEVICE_INFO(byte[] buffer, IBluetoothDeviceInfo dev)
        {
            // XXXX - Testing only, at least delete the "Console.WriteLine" before use. - XXXX
            IntPtr pBlob = Marshal32.ReadIntPtr(buffer, WqsOffset.lpBlob_56);
            if (pBlob != IntPtr.Zero) {
                BLOB blob = (BLOB)Marshal.PtrToStructure(pBlob, typeof(BLOB));
                if (blob.pBlobData != IntPtr.Zero) {
                    BTH_DEVICE_INFO bdi = (BTH_DEVICE_INFO)Marshal.PtrToStructure(blob.pBlobData, typeof(BTH_DEVICE_INFO));
                    BDIF flags = bdi.flags;
                    Console.WriteLine("[BTH_DEVICE_INFO: {0:X12}, '{1}' = 0x{2:X4}]", bdi.address, flags, bdi.flags);
                    Trace.Assert((flags & ~BDIFMasks.AllOrig) == 0, "*Are* new flags there!");
                }
            }
        }
#endif

#if NETCF
        private static List_IBluetoothDeviceInfo WinCEReadKnownDevicesFromRegistry()
        {
            List_IBluetoothDeviceInfo known = new List_IBluetoothDeviceInfo();

            //open bluetooth device key
            RegistryKey devkey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Bluetooth\\Device");
            //bool addFromRegistry = authenticated || remembered;

            if (devkey != null) {

                //enumerate the keys
                foreach (string devid in devkey.GetSubKeyNames()) {
                    BluetoothAddress address;

                    if (BluetoothAddress.TryParse(devid, out address)) {
                        //get friendly name
                        RegistryKey thisdevkey = devkey.OpenSubKey(devid);
                        string name = thisdevkey.GetValue("name", "").ToString();
                        uint classOfDevice = Convert.ToUInt32(thisdevkey.GetValue("class", 0));
                        thisdevkey.Close();

                        //add to collection
                        IBluetoothDeviceInfo thisdevice = new WindowsBluetoothDeviceInfo(address, name, classOfDevice, true);
                        known.Add(thisdevice);
                        /*
                                                    int devindex = al.IndexOf(thisdevice);

                                                    if (devindex == -1)
                                                    {
                                                        //if we intended to search for authenticated devices add this one to the collection
                                                        if (addFromRegistry)
                                                        {
                                                            al.Add(thisdevice);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        if (addFromRegistry)
                                                        {
                                                            //set authenticated flag on existing discovered device
                                                            ((IBluetoothDeviceInfo)al[devindex]).SetAuthenticated();
                                                        }
                                                        else
                                                        {
                                                            //we want to exclude already authenticated devices so remove it from the collection
                                                            al.RemoveAt(devindex);
                                                        }
                                                    }
                        */
                    }
                }

                devkey.Close();
            }
            return known;
        }
#endif

#if !V1
        IAsyncResult IBluetoothClient.BeginDiscoverDevices(int maxDevices,
            bool authenticated, bool remembered, bool unknown, bool discoverableOnly,
            AsyncCallback callback, object state)
        {
            var args = new DiscoDevsParams(maxDevices,
                    authenticated, remembered, unknown, discoverableOnly,
                    DateTime.MinValue);
            AsyncResult_BeginDiscoverDevices ar = new AsyncResult_BeginDiscoverDevices(
                callback, state, args);
            System.Threading.ThreadPool.QueueUserWorkItem(BeginDiscoverDevices_Runner, ar);
            return ar;
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        void BeginDiscoverDevices_Runner(object state)
        {
            AsyncResult_BeginDiscoverDevices ar = (AsyncResult_BeginDiscoverDevices)state;
            try {
                IBluetoothDeviceInfo[] result = DiscoverDevices(ar.BeginParameters.maxDevices, 
                    ar.BeginParameters.authenticated, ar.BeginParameters.remembered,
                    ar.BeginParameters.unknown, ar.BeginParameters.discoverableOnly);
                ar.SetAsCompleted(result, false);
            } catch (Exception ex) {
                ar.SetAsCompleted(ex, false);
            }
        }

        IBluetoothDeviceInfo[] IBluetoothClient.EndDiscoverDevices(IAsyncResult asyncResult)
        {
            AsyncResult_BeginDiscoverDevices ar = (AsyncResult_BeginDiscoverDevices)asyncResult;
            return ar.EndInvoke();
        }
#endif
    #endregion


        #region Active
        private bool active = false;

        /// <summary>
        /// Gets or set a value that indicates whether a connection has been made.
        /// </summary>
        protected bool Active
        {
            get
            {
                return active;
            }
            set
            {
                active = value;
            }
        }
        #endregion

    #region Available
    /// <summary>
    /// Gets the amount of data that has been received from the network and is available to be read.
    /// </summary>
    /// <value>The number of bytes of data received from the network and available to be read.</value>
    /// <exception cref="ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
    public int Available
    {
      get
      {
                EnsureNotDisposed();
                return clientSocket.Available;
      }
    }
    #endregion

    #region Client

        private Socket clientSocket;

    /// <summary>
    /// Gets or sets the underlying <see cref="Socket"/>.
    /// </summary>
    public Socket Client
    {
      get
      {
                return clientSocket;
      }
            set
            {
                this.clientSocket = value;
            }

    }

    #endregion

    #region Connect
    /// <summary>
    /// Connects a client to a specified endpoint.
    /// </summary>
        /// <param name="remoteEP">A <see cref="BluetoothEndPoint"/> that represents the remote device.</param>
        public void Connect(BluetoothEndPoint remoteEP)
    {
            EnsureNotDisposed();
            if (remoteEP == null)
            {
                throw new ArgumentNullException("remoteEP");
            }

            Connect_StartAuthenticator(remoteEP);
            try {
                clientSocket.Connect(remoteEP);
                active = true;
            } finally {
                Connect_StopAuthenticator();
            }
    }

        #region Begin Connect
        /// <summary>
        /// Begins an asynchronous request for a remote host connection.
        /// The remote host is specified by a <see cref="BluetoothEndPoint"/>. 
        /// </summary>
        /// <param name="remoteEP">A <see cref="BluetoothEndPoint"/> containing the 
        /// address and UUID of the remote service.</param>
        /// <param name="requestCallback">An AsyncCallback delegate that references the method to invoke when the operation is complete.</param>
        /// <param name="state">A user-defined object that contains information about the connect operation.
        /// This object is passed to the requestCallback delegate when the operation is complete.</param>
        /// <returns></returns>
        public IAsyncResult BeginConnect(BluetoothEndPoint remoteEP, AsyncCallback requestCallback, object state)
        {
            EnsureNotDisposed();
            Connect_StartAuthenticator(remoteEP);
            return this.Client.BeginConnect(remoteEP, requestCallback, state);
        }
        #endregion

        #region End Connect
        /// <summary>
        /// Asynchronously accepts an incoming connection attempt.
        /// </summary>
        /// <param name="asyncResult">An <see cref="IAsyncResult"/> object returned by a call to 
        /// <see cref="M:BeginConnect(InTheHand.Net.Sockets.BluetoothEndPoint,System.AsyncCallback,System.Object)"/>
        /// / <see cref="M:BeginConnect(InTheHand.Net.Sockets.BluetoothAddress,System.Guid,System.AsyncCallback,System.Object)"/>.
        /// </param>
        public void EndConnect(IAsyncResult asyncResult)
        {
            try {
                Socket sock = this.Client;
                if (sock == null) {
                    Debug.Assert(cleanedUp, "!cleanedUp");
                    throw new ObjectDisposedException("BluetoothClient");
                } else {
                    sock.EndConnect(asyncResult);
                }
                this.active = true;
            } finally {
                Connect_StopAuthenticator();
            }
        }
        #endregion

        #endregion

        #region Connected
        /// <summary>
    /// Gets a value indicating whether the underlying <see cref="Socket"/> for a <see cref="BluetoothClient"/> is connected to a remote host.
    /// </summary>
    /// <value>true if the <see cref="Client"/> socket was connected to a remote resource as of the most recent operation; otherwise, false.</value>
    public bool Connected
    {
      get
      {
                if (clientSocket == null)
                    return false;
        return clientSocket.Connected;
      }
    }
    #endregion

    #region Get Stream

        private NetworkStream dataStream;

    /// <summary>
    /// Gets the underlying stream of data.
    /// </summary>
    /// <returns>The underlying <see cref="NetworkStream"/>.</returns>
    /// <remarks><see cref="GetStream"/> returns a <see cref="NetworkStream"/> that you can use to send and receive data.
    /// 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.
        /// <para>You must call the <see cref="Connect(InTheHand.Net.BluetoothEndPoint)"/> / <see cref="M:Connect(InTheHand.Net.BluetoothAddress,System.Guid)"/>
        /// method first, or the <see cref="GetStream"/> method will throw an <see cref="InvalidOperationException"/>.
    /// After you have obtained the <see cref="NetworkStream"/>, call the <see cref="NetworkStream.Write"/> method to send data to the remote host.
    /// Call the <see cref="NetworkStream.Read"/> method to receive data arriving from the remote host.
    /// Both of these methods block until the specified operation is performed.
    /// You can avoid blocking on a read operation by checking the <see cref="NetworkStream.DataAvailable"/> property.
    /// A true value means that data has arrived from the remote host and is available for reading.
    /// In this case, <see cref="NetworkStream.Read"/> is guaranteed to complete immediately.
    /// If the remote host has shutdown its connection, <see cref="NetworkStream.Read"/> will immediately return with zero bytes.</para></remarks>
    /// <exception cref="InvalidOperationException">The <see cref="BluetoothClient"/> is not connected to a remote host.</exception>
    /// <exception cref="ObjectDisposedException">The <see cref="BluetoothClient"/> has been closed.</exception>
    public NetworkStream GetStream()
    {
            EnsureNotDisposed();
            if (!this.Client.Connected)
            {
                throw new InvalidOperationException("The operation is not allowed on non-connected sockets.");
            }

            if (dataStream == null)
            {
                dataStream = new NetworkStream(this.Client, true);
            }

            return dataStream;
    }

#if TEST_EARLY
        public Stream GetStream2()
        {
            return GetStream();
        }
#endif
#endregion

        public LingerOption LingerState
        {
#if !NETCF
            get { return Client.LingerState; }
            set { Client.LingerState = value; }
#else
            get
            {
                return (LingerOption)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
            }
            set
            {
                Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
            }
#endif
        }
  

    #region Authenticate
    /// <summary>
    /// Gets or sets the authentication state of the current connect or behaviour to use when connection is established.
    /// </summary>
    /// <remarks>
    /// For disconnected sockets, specifies that authentication is required in order for a connect or accept operation to complete successfully.
    /// Setting this option actively initiates authentication during connection establishment, if the two Bluetooth devices were not previously authenticated.
    /// The user interface for passkey exchange, if necessary, is provided by the operating system outside the application context.
    /// For outgoing connections that require authentication, the connect operation fails with WSAEACCES if authentication is not successful.
    /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
    /// For incoming connections, the connection is rejected if authentication cannot be established and returns a WSAEHOSTDOWN error.
    /// </remarks>
    public bool Authenticate
    {
            get { return m_optionHelper.Authenticate; }
            set { m_optionHelper.Authenticate = value; }
    }
    #endregion

    #region Encrypt
    /// <summary>
    /// On unconnected sockets, enforces encryption to establish a connection.
    /// Encryption is only available for authenticated connections.
    /// For incoming connections, a connection for which encryption cannot be established is automatically rejected and returns WSAEHOSTDOWN as the error.
    /// For outgoing connections, the connect function fails with WSAEACCES if encryption cannot be established.
    /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
    /// </summary>
    public bool Encrypt
    {
            get { return m_optionHelper.Encrypt; }
            set { m_optionHelper.Encrypt = value; }
    }
    #endregion

    
    #region Link Key
    /// <summary>
    /// Returns link key associated with peer Bluetooth device.
    /// </summary>
    public Guid LinkKey
    {
      get
      {
                EnsureNotDisposed();
                byte[] link = clientSocket.GetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.GetLink, 32);

        byte[] bytes = new byte[16];
        Buffer.BlockCopy(link, 16, bytes, 0, 16);
        return new Guid(bytes);
      }
    }
    #endregion

    #region Link Policy
    /// <summary>
    /// Returns the Link Policy of the current connection.
    /// </summary>
    public LinkPolicy LinkPolicy
    {
      get
      {
                EnsureNotDisposed();
                byte[] policy = clientSocket.GetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.GetLinkPolicy, 4);
        return (LinkPolicy)BitConverter.ToInt32(policy, 0);
      }
    }
    #endregion

  
    #region Set PIN
        /// <summary>
        /// Sets the PIN associated with the currently connected device.
        /// </summary>
        /// <param name="pin">PIN which must be composed of 1 to 16 ASCII characters.</param>
        /// <remarks>Assigning null (Nothing in VB) or an empty String will revoke the PIN.</remarks>
        public void SetPin(string pin)
        {
            if (!Connected) {
#if WinXP
                m_pinForConnect = pin;
#else
                SetPin(null, pin);
#endif
            } else {
                EndPoint rep = clientSocket.RemoteEndPoint;
                BluetoothAddress addr = null;
                if (rep != null)
                    addr = ((BluetoothEndPoint)rep).Address;
                if (addr == null)
                    throw new InvalidOperationException(
                        "The socket needs to be connected to detect the remote device"
                        + ", use the other SetPin method..");
                SetPin(addr, pin);
            }
        }

    /// <summary>
    /// Set or change the PIN to be used with a specific remote device.
    /// </summary>
    /// <param name="device">Address of Bluetooth device.</param>
    /// <param name="pin">PIN string consisting of 1 to 16 ASCII characters.</param>
        /// <remarks>Assigning null (Nothing in VB) or an empty String will revoke the PIN.</remarks>
    public void SetPin(BluetoothAddress device, string pin)
        {
            m_optionHelper.SetPin(device, pin);
        }

        private void Connect_StartAuthenticator(BluetoothEndPoint remoteEP)
        {
#if WinXP
            if (m_pinForConnect != null) {
                SetPin(remoteEP.Address, m_pinForConnect);
            }
#endif
        }

        private void Connect_StopAuthenticator()
        {
#if WinXP
            if (m_pinForConnect != null) {
                SetPin(null, null);
            }
#endif
        }
        #endregion


    #region Remote Machine Name
        public BluetoothEndPoint RemoteEndPoint
        {
            get
            {
                EnsureNotDisposed();
                return (BluetoothEndPoint)clientSocket.RemoteEndPoint;
            }
        }

    /// <summary>
    /// Gets the name of the remote device.
    /// </summary>
    public string RemoteMachineName
    {
      get
      {
                EnsureNotDisposed();
                return GetRemoteMachineName(clientSocket);
      }
    }
    
    /// <summary>
    /// Gets the name of the specified remote device.
    /// </summary>
    /// <param name="a">Address of remote device.</param>
    /// <returns>Friendly name of specified device.</returns>
    public string GetRemoteMachineName(BluetoothAddress a)
    {
#if WinXP
            IBluetoothDeviceInfo bdi = new WindowsBluetoothDeviceInfo(a);
            return bdi.DeviceName;
#else
      byte[] buffer = new byte[504];
      //copy remote device address to buffer
      Buffer.BlockCopy(a.ToByteArray(), 0, buffer, 0, 6);

      try
      {
                clientSocket.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.ReadRemoteName, buffer);
        string name = string.Empty;
                name = System.Text.Encoding.Unicode.GetString(buffer, 8, 496);
        
        int offset = name.IndexOf('\0');
        if(offset > -1)
        {
          name = name.Substring(0, offset);
        }

        return name;
      }
      catch(SocketException ex)
      {
                System.Diagnostics.Debug.WriteLine("BluetoothClient GetRemoteMachineName(addr) ReadRemoteName failed: " + ex.Message);
        return null;
      }
#endif
    }

    /// <summary>
    /// Gets the name of a device by a specified socket.
    /// </summary>
    /// <param name="s"> A <see cref="Socket"/>.</param>
    /// <returns>Returns a string value of the computer or device name.</returns>
    public static string GetRemoteMachineName(Socket s)
    {
#if WinXP
            IBluetoothDeviceInfo bdi = new WindowsBluetoothDeviceInfo(((BluetoothEndPoint)s.RemoteEndPoint).Address);
            return bdi.DeviceName;
#else
      byte[] buffer = new byte[504];
      //copy remote device address to buffer
      Buffer.BlockCopy(((BluetoothEndPoint)s.RemoteEndPoint).Address.ToByteArray(), 0, buffer, 0, 6);

            string name = "";

      try
      {
                s.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.ReadRemoteName, buffer);
        name = System.Text.Encoding.Unicode.GetString(buffer, 8, 496);
        
        int offset = name.IndexOf('\0');
        if(offset > -1)
        {
          name = name.Substring(0, offset);
        }

        return name;
      }
      catch(SocketException ex)
      {
                System.Diagnostics.Debug.WriteLine("BluetoothClient GetRemoteMachineName(socket) ReadRemoteName failed: " + ex.Message);
                return null;
      }
#endif
    }
    #endregion

    #region IDisposable Members

    /// <summary>
        /// Releases the unmanaged resources used by the BluetoothClient and optionally releases the managed resources.
    /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
    protected virtual void Dispose(bool disposing)
    {
            if(!cleanedUp)
            {
                if (disposing)
                {
                    IDisposable idStream = dataStream;
                    if (idStream != null)
                    {
                        //dispose the stream which will also close the socket
                        idStream.Dispose();
                    }
                    else
                    {
                        if (this.Client != null)
                        {
                            this.Client.Close();
                            this.Client = null;
                        }
                    }
                    // TODO ??? m_optionHelper.Dispose();
                }

                cleanedUp = true;
            }
    }

        private void EnsureNotDisposed()
        {
            Debug.Assert(cleanedUp == (clientSocket == null),"always consistent!! ("
                + cleanedUp + " != " + (clientSocket == null) + ")");
            if (cleanedUp || (clientSocket == null))
                throw new ObjectDisposedException("BluetoothClient");
        }

        /// <summary>
        /// Closes the <see cref="BluetoothClient"/> and the underlying connection.
        /// </summary>
        /// -
        /// <seealso cref="M:InTheHand.Net.Sockets.BluetoothClient.Close"/>
        public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Frees resources used by the <see cref="BluetoothClient"/> class.
    /// </summary>
    ~SocketBluetoothClient()
    {
      Dispose(false);
    }

    #endregion

        #region Throw SocketException For HR
        internal static void ThrowSocketExceptionForHR(int errorCode)
        {
            if (errorCode < 0)
            {
                int socketerror = 0;
                socketerror = Marshal.GetLastWin32Error();

                throw new SocketException(socketerror);
            }
        }

        internal static void ThrowSocketExceptionForHrExceptFor(int errorCode, params int[] nonErrorCodes)
        {
            if (errorCode < 0) {
                int socketerror = 0;
                socketerror = Marshal.GetLastWin32Error();
                if (-1 != Array.IndexOf(nonErrorCodes, socketerror, 0, nonErrorCodes.Length)) {
                    return;
                }
                throw new SocketException(socketerror);
            }
        }
        #endregion

        internal class SocketOptionHelper
        {
            readonly Socket m_socket;
#if ! WinCE
            private bool authenticate = false;
            private BluetoothWin32Authentication m_authenticator;
        
#endif
            private bool encrypt = false;

            internal SocketOptionHelper(Socket socket)
            {
                m_socket = socket;
            }

            #region Authenticate
            /// <summary>
            /// Gets or sets the authentication state of the current connect or behaviour to use when connection is established.
            /// </summary>
            /// <remarks>
            /// For disconnected sockets, specifies that authentication is required in order for a connect or accept operation to complete successfully.
            /// Setting this option actively initiates authentication during connection establishment, if the two Bluetooth devices were not previously authenticated.
            /// The user interface for passkey exchange, if necessary, is provided by the operating system outside the application context.
            /// For outgoing connections that require authentication, the connect operation fails with WSAEACCES if authentication is not successful.
            /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
            /// For incoming connections, the connection is rejected if authentication cannot be established and returns a WSAEHOSTDOWN error.
            /// </remarks>
            public bool Authenticate
            {
                get
                {
#if NETCF
                    byte[] authbytes = m_socket.GetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.GetAuthenticationEnabled, 4);
                    int auth = BitConverter.ToInt32(authbytes, 0);
                    return (auth==0) ? false : true;
#else
                    return authenticate;
#endif
                }
                set
                {
#if NETCF
                    m_socket.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.SetAuthenticationEnabled, (int)(value ? 1 : 0));
#else
                    m_socket.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.XPAuthenticate, value);
                    authenticate = value;
#endif
                }
            }
            #endregion

            #region Encrypt
            /// <summary>
            /// On unconnected sockets, enforces encryption to establish a connection.
            /// Encryption is only available for authenticated connections.
            /// For incoming connections, a connection for which encryption cannot be established is automatically rejected and returns WSAEHOSTDOWN as the error.
            /// For outgoing connections, the connect function fails with WSAEACCES if encryption cannot be established.
            /// In response, the application may prompt the user to authenticate the two Bluetooth devices before connection.
            /// </summary>
            public bool Encrypt
            {
                get { return encrypt; }
                set
                {
                    m_socket.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.Encrypt, (int)(value ? 1 : 0));
                    encrypt = value;
                }
            }
            #endregion

            #region Set Pin
            public void SetPin(BluetoothAddress device, string pin)
            {
#if WinXP
                if (pin != null) {
                    m_authenticator = new BluetoothWin32Authentication(device, pin);
                } else {
                    if (m_authenticator != null) {
                        m_authenticator.Dispose();
                    }
                }
#else
                byte[] link = new byte[32];

                //copy remote device address
                if (device != null)
                {
                    Buffer.BlockCopy(device.ToByteArray(), 0, link, 8, 6);
                }

                //copy PIN
                if (pin != null & pin.Length > 0)
                {
                    if (pin.Length > 16)
                    {
                        throw new ArgumentOutOfRangeException("PIN must be between 1 and 16 ASCII characters");
                    }
                    //copy pin bytes
                    byte[] pinbytes = System.Text.Encoding.ASCII.GetBytes(pin);
                    Buffer.BlockCopy(pinbytes, 0, link, 16, pin.Length);
                    BitConverter.GetBytes(pin.Length).CopyTo(link, 0);
                }

                m_socket.SetSocketOption(BluetoothSocketOptionLevel.RFComm, BluetoothSocketOptionName.SetPin, link);
#endif
            }
            #endregion

        }//class--SocketOptionHelper

    }//class--BluetoothClient

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.