dom/bluetooth/bluedroid/BluetoothSocket.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "BluetoothSocket.h"
     9 #include <hardware/bluetooth.h>
    10 #include <hardware/bt_sock.h>
    11 #include <sys/socket.h>
    13 #include "base/message_loop.h"
    14 #include "BluetoothSocketObserver.h"
    15 #include "BluetoothUtils.h"
    16 #include "mozilla/FileUtils.h"
    17 #include "mozilla/RefPtr.h"
    18 #include "nsThreadUtils.h"
    19 #include "nsXULAppAPI.h"
    21 #define FIRST_SOCKET_INFO_MSG_LENGTH 4
    22 #define TOTAL_SOCKET_INFO_LENGTH 20
    24 using namespace mozilla::ipc;
    25 USING_BLUETOOTH_NAMESPACE
    27 static const size_t MAX_READ_SIZE = 1 << 16;
    28 static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
    29   0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
    30   0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
    31 };
    32 static const btsock_interface_t* sBluetoothSocketInterface = nullptr;
    34 // helper functions
    35 static bool
    36 EnsureBluetoothSocketHalLoad()
    37 {
    38   if (sBluetoothSocketInterface) {
    39     return true;
    40   }
    42   const bt_interface_t* btInf = GetBluetoothInterface();
    43   NS_ENSURE_TRUE(btInf, false);
    45   sBluetoothSocketInterface =
    46     (btsock_interface_t *) btInf->get_profile_interface(BT_PROFILE_SOCKETS_ID);
    47   NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
    49   return true;
    50 }
    52 static int16_t
    53 ReadInt16(const uint8_t* aData, size_t* aOffset)
    54 {
    55   int16_t value = (aData[*aOffset + 1] << 8) | aData[*aOffset];
    57   *aOffset += 2;
    58   return value;
    59 }
    61 static int32_t
    62 ReadInt32(const uint8_t* aData, size_t* aOffset)
    63 {
    64   int32_t value = (aData[*aOffset + 3] << 24) |
    65                   (aData[*aOffset + 2] << 16) |
    66                   (aData[*aOffset + 1] << 8) |
    67                   aData[*aOffset];
    68   *aOffset += 4;
    69   return value;
    70 }
    72 static void
    73 ReadBdAddress(const uint8_t* aData, size_t* aOffset, nsAString& aDeviceAddress)
    74 {
    75   char bdstr[18];
    76   sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
    77           aData[*aOffset], aData[*aOffset + 1], aData[*aOffset + 2],
    78           aData[*aOffset + 3], aData[*aOffset + 4], aData[*aOffset + 5]);
    80   aDeviceAddress.AssignLiteral(bdstr);
    81   *aOffset += 6;
    82 }
    84 class mozilla::dom::bluetooth::DroidSocketImpl
    85     : public MessageLoopForIO::Watcher
    86 {
    87 public:
    88   DroidSocketImpl(BluetoothSocket* aConsumer, int aFd)
    89     : mConsumer(aConsumer)
    90     , mReadMsgForClientFd(false)
    91     , mIOLoop(nullptr)
    92     , mFd(aFd)
    93     , mShuttingDownOnIOThread(false)
    94     , mChannel(0)
    95     , mAuth(false)
    96     , mEncrypt(false)
    97   {
    98   }
   100   DroidSocketImpl(BluetoothSocket* aConsumer,
   101                   int aChannel, bool aAuth, bool aEncrypt)
   102     : mConsumer(aConsumer)
   103     , mReadMsgForClientFd(false)
   104     , mIOLoop(nullptr)
   105     , mFd(-1)
   106     , mShuttingDownOnIOThread(false)
   107     , mChannel(aChannel)
   108     , mAuth(aAuth)
   109     , mEncrypt(aEncrypt)
   110   { }
   112   DroidSocketImpl(BluetoothSocket* aConsumer, const nsAString& aDeviceAddress,
   113                   int aChannel, bool aAuth, bool aEncrypt)
   114     : mConsumer(aConsumer)
   115     , mReadMsgForClientFd(false)
   116     , mIOLoop(nullptr)
   117     , mFd(-1)
   118     , mShuttingDownOnIOThread(false)
   119     , mDeviceAddress(aDeviceAddress)
   120     , mChannel(aChannel)
   121     , mAuth(aAuth)
   122     , mEncrypt(aEncrypt)
   123   {
   124     MOZ_ASSERT(!mDeviceAddress.IsEmpty());
   125   }
   127   ~DroidSocketImpl()
   128   {
   129     MOZ_ASSERT(NS_IsMainThread());
   130   }
   132   void QueueWriteData(UnixSocketRawData* aData)
   133   {
   134     mOutgoingQ.AppendElement(aData);
   135     OnFileCanWriteWithoutBlocking(mFd);
   136   }
   138   bool IsShutdownOnMainThread()
   139   {
   140     MOZ_ASSERT(NS_IsMainThread());
   141     return mConsumer == nullptr;
   142   }
   144   bool IsShutdownOnIOThread()
   145   {
   146     return mShuttingDownOnIOThread;
   147   }
   149   void ShutdownOnMainThread()
   150   {
   151     MOZ_ASSERT(NS_IsMainThread());
   152     MOZ_ASSERT(!IsShutdownOnMainThread());
   153     mConsumer = nullptr;
   154   }
   156   void ShutdownOnIOThread()
   157   {
   158     MOZ_ASSERT(!NS_IsMainThread());
   159     MOZ_ASSERT(!mShuttingDownOnIOThread);
   161     mReadWatcher.StopWatchingFileDescriptor();
   162     mWriteWatcher.StopWatchingFileDescriptor();
   164     mShuttingDownOnIOThread = true;
   165   }
   167   void Connect();
   168   void Listen();
   170   void SetUpIO(bool aWrite)
   171   {
   172     MOZ_ASSERT(!mIOLoop);
   173     MOZ_ASSERT(mFd >= 0);
   174     mIOLoop = MessageLoopForIO::current();
   176     // Set up a read watch
   177     mIOLoop->WatchFileDescriptor(mFd,
   178                                  true,
   179                                  MessageLoopForIO::WATCH_READ,
   180                                  &mReadWatcher,
   181                                  this);
   183     if (aWrite) {
   184       // Set up a write watch
   185       mIOLoop->WatchFileDescriptor(mFd.get(),
   186                                    false,
   187                                    MessageLoopForIO::WATCH_WRITE,
   188                                    &mWriteWatcher,
   189                                    this);
   190     }
   191   }
   193   void ConnectClientFd()
   194   {
   195     // Stop current read watch
   196     mReadWatcher.StopWatchingFileDescriptor();
   197     mIOLoop = nullptr;
   199     // Restart read & write watch on client fd
   200     SetUpIO(true);
   201   }
   203   /**
   204    * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
   205    * directly from main thread. All non-main-thread accesses should happen with
   206    * mImpl as container.
   207    */
   208   RefPtr<BluetoothSocket> mConsumer;
   210   /**
   211    * If true, read message header to get client fd.
   212    */
   213   bool mReadMsgForClientFd;
   215 private:
   216   /**
   217    * libevent triggered functions that reads data from socket when available and
   218    * guarenteed non-blocking. Only to be called on IO thread.
   219    *
   220    * @param aFd [in] File descriptor to read from
   221    */
   222   virtual void OnFileCanReadWithoutBlocking(int aFd);
   224   /**
   225    * libevent or developer triggered functions that writes data to socket when
   226    * available and guarenteed non-blocking. Only to be called on IO thread.
   227    *
   228    * @param aFd [in] File descriptor to read from
   229    */
   230   virtual void OnFileCanWriteWithoutBlocking(int aFd);
   232   /**
   233    * Read message to get data and client fd wrapped in message header
   234    *
   235    * @param aFd     [in]  File descriptor to read message from
   236    * @param aBuffer [out] Data buffer read
   237    * @param aLength [out] Number of bytes read
   238    */
   239   ssize_t ReadMsg(int aFd, void *aBuffer, size_t aLength);
   241   /**
   242    * IO Loop pointer. Must be initalized and called from IO thread only.
   243    */
   244   MessageLoopForIO* mIOLoop;
   246   /**
   247    * Raw data queue. Must be pushed/popped from IO thread only.
   248    */
   249   typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue;
   250   UnixSocketRawDataQueue mOutgoingQ;
   252   /**
   253    * Read watcher for libevent. Only to be accessed on IO Thread.
   254    */
   255   MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
   257   /**
   258    * Write watcher for libevent. Only to be accessed on IO Thread.
   259    */
   260   MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
   262   /**
   263    * File descriptor to read from/write to. Connection happens on user provided
   264    * thread. Read/write/close happens on IO thread.
   265    */
   266   mozilla::ScopedClose mFd;
   268   /**
   269    * If true, do not requeue whatever task we're running
   270    */
   271   bool mShuttingDownOnIOThread;
   273   nsString mDeviceAddress;
   274   int mChannel;
   275   bool mAuth;
   276   bool mEncrypt;
   277 };
   279 template<class T>
   280 class DeleteInstanceRunnable : public nsRunnable
   281 {
   282 public:
   283   DeleteInstanceRunnable(T* aInstance)
   284   : mInstance(aInstance)
   285   { }
   287   NS_IMETHOD Run()
   288   {
   289     delete mInstance;
   291     return NS_OK;
   292   }
   294 private:
   295   T* mInstance;
   296 };
   298 class RequestClosingSocketTask : public nsRunnable
   299 {
   300 public:
   301   RequestClosingSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl)
   302   {
   303     MOZ_ASSERT(aImpl);
   304   }
   306   NS_IMETHOD Run()
   307   {
   308     MOZ_ASSERT(NS_IsMainThread());
   310     if (mImpl->IsShutdownOnMainThread()) {
   311       NS_WARNING("CloseSocket has already been called!");
   312       // Since we've already explicitly closed and the close happened before
   313       // this, this isn't really an error. Since we've warned, return OK.
   314       return NS_OK;
   315     }
   317     // Start from here, same handling flow as calling CloseSocket() from
   318     // upper layer
   319     mImpl->mConsumer->CloseDroidSocket();
   320     return NS_OK;
   321   }
   322 private:
   323   DroidSocketImpl* mImpl;
   324 };
   326 class ShutdownSocketTask : public Task {
   327   virtual void Run()
   328   {
   329     MOZ_ASSERT(!NS_IsMainThread());
   331     // At this point, there should be no new events on the IO thread after this
   332     // one with the possible exception of a SocketAcceptTask that
   333     // ShutdownOnIOThread will cancel for us. We are now fully shut down, so we
   334     // can send a message to the main thread that will delete mImpl safely knowing
   335     // that no more tasks reference it.
   336     mImpl->ShutdownOnIOThread();
   338     nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable<
   339                                   mozilla::dom::bluetooth::DroidSocketImpl>(mImpl));
   340     nsresult rv = NS_DispatchToMainThread(t);
   341     NS_ENSURE_SUCCESS_VOID(rv);
   342   }
   344   DroidSocketImpl* mImpl;
   346 public:
   347   ShutdownSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { }
   348 };
   350 class SocketReceiveTask : public nsRunnable
   351 {
   352 public:
   353   SocketReceiveTask(DroidSocketImpl* aImpl, UnixSocketRawData* aData) :
   354     mImpl(aImpl),
   355     mRawData(aData)
   356   {
   357     MOZ_ASSERT(aImpl);
   358     MOZ_ASSERT(aData);
   359   }
   361   NS_IMETHOD Run()
   362   {
   363     MOZ_ASSERT(NS_IsMainThread());
   364     if (mImpl->IsShutdownOnMainThread()) {
   365       NS_WARNING("mConsumer is null, aborting receive!");
   366       // Since we've already explicitly closed and the close happened before
   367       // this, this isn't really an error. Since we've warned, return OK.
   368       return NS_OK;
   369     }
   371     MOZ_ASSERT(mImpl->mConsumer);
   372     mImpl->mConsumer->ReceiveSocketData(mRawData);
   373     return NS_OK;
   374   }
   375 private:
   376   DroidSocketImpl* mImpl;
   377   nsAutoPtr<UnixSocketRawData> mRawData;
   378 };
   380 class SocketSendTask : public Task
   381 {
   382 public:
   383   SocketSendTask(BluetoothSocket* aConsumer, DroidSocketImpl* aImpl,
   384                  UnixSocketRawData* aData)
   385     : mConsumer(aConsumer),
   386       mImpl(aImpl),
   387       mData(aData)
   388   {
   389     MOZ_ASSERT(aConsumer);
   390     MOZ_ASSERT(aImpl);
   391     MOZ_ASSERT(aData);
   392   }
   394   void
   395   Run()
   396   {
   397     MOZ_ASSERT(!NS_IsMainThread());
   398     MOZ_ASSERT(!mImpl->IsShutdownOnIOThread());
   400     mImpl->QueueWriteData(mData);
   401   }
   403 private:
   404   nsRefPtr<BluetoothSocket> mConsumer;
   405   DroidSocketImpl* mImpl;
   406   UnixSocketRawData* mData;
   407 };
   409 class DroidSocketImplTask : public CancelableTask
   410 {
   411 public:
   412   DroidSocketImpl* GetDroidSocketImpl() const
   413   {
   414     return mDroidSocketImpl;
   415   }
   416   void Cancel() MOZ_OVERRIDE
   417   {
   418     mDroidSocketImpl = nullptr;
   419   }
   420   bool IsCanceled() const
   421   {
   422     return !mDroidSocketImpl;
   423   }
   424 protected:
   425   DroidSocketImplTask(DroidSocketImpl* aDroidSocketImpl)
   426   : mDroidSocketImpl(aDroidSocketImpl)
   427   {
   428     MOZ_ASSERT(mDroidSocketImpl);
   429   }
   430 private:
   431   DroidSocketImpl* mDroidSocketImpl;
   432 };
   434 class SocketConnectTask : public DroidSocketImplTask
   435 {
   436 public:
   437   SocketConnectTask(DroidSocketImpl* aDroidSocketImpl)
   438   : DroidSocketImplTask(aDroidSocketImpl)
   439   { }
   441   void Run() MOZ_OVERRIDE
   442   {
   443     MOZ_ASSERT(!NS_IsMainThread());
   444     MOZ_ASSERT(!IsCanceled());
   445     GetDroidSocketImpl()->Connect();
   446   }
   447 };
   449 class SocketListenTask : public DroidSocketImplTask
   450 {
   451 public:
   452   SocketListenTask(DroidSocketImpl* aDroidSocketImpl)
   453   : DroidSocketImplTask(aDroidSocketImpl)
   454   { }
   456   void Run() MOZ_OVERRIDE
   457   {
   458     MOZ_ASSERT(!NS_IsMainThread());
   459     if (!IsCanceled()) {
   460       GetDroidSocketImpl()->Listen();
   461     }
   462   }
   463 };
   465 class SocketConnectClientFdTask : public Task
   466 {
   467   virtual void Run()
   468   {
   469     MOZ_ASSERT(!NS_IsMainThread());
   470     mImpl->ConnectClientFd();
   471   }
   473   DroidSocketImpl* mImpl;
   474 public:
   475   SocketConnectClientFdTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { }
   476 };
   478 void
   479 DroidSocketImpl::Connect()
   480 {
   481   MOZ_ASSERT(sBluetoothSocketInterface);
   483   bt_bdaddr_t remoteBdAddress;
   484   StringToBdAddressType(mDeviceAddress, &remoteBdAddress);
   486   // TODO: uuid as argument
   487   int fd = -1;
   488   bt_status_t status =
   489     sBluetoothSocketInterface->connect(&remoteBdAddress,
   490                                        BTSOCK_RFCOMM,
   491                                        UUID_OBEX_OBJECT_PUSH,
   492                                        mChannel,
   493                                        &fd,
   494                                        (BTSOCK_FLAG_ENCRYPT * mEncrypt) |
   495                                        (BTSOCK_FLAG_AUTH * mAuth));
   496   NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
   497   NS_ENSURE_TRUE_VOID(fd >= 0);
   499   mFd = fd;
   501   MOZ_ASSERT(!mIOLoop);
   502   mIOLoop = MessageLoopForIO::current();
   504   // Set up a read watch
   505   mIOLoop->WatchFileDescriptor(mFd.get(),
   506                                true,
   507                                MessageLoopForIO::WATCH_READ,
   508                                &mReadWatcher,
   509                                this);
   510   // Set up a write watch
   511   mIOLoop->WatchFileDescriptor(mFd.get(),
   512                                false,
   513                                MessageLoopForIO::WATCH_WRITE,
   514                                &mWriteWatcher,
   515                                this);
   516 }
   518 void
   519 DroidSocketImpl::Listen()
   520 {
   521   MOZ_ASSERT(sBluetoothSocketInterface);
   523   // TODO: uuid and service name as arguments
   525   int fd = -1;
   526   bt_status_t status =
   527     sBluetoothSocketInterface->listen(BTSOCK_RFCOMM,
   528                                       "OBEX Object Push",
   529                                       UUID_OBEX_OBJECT_PUSH,
   530                                       mChannel,
   531                                       &fd,
   532                                       (BTSOCK_FLAG_ENCRYPT * mEncrypt) |
   533                                       (BTSOCK_FLAG_AUTH * mAuth));
   534   NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
   535   NS_ENSURE_TRUE_VOID(fd >= 0);
   537   mFd = fd;
   539   MOZ_ASSERT(!mIOLoop);
   540   mIOLoop = MessageLoopForIO::current();
   542   // Set up a read watch
   543   mIOLoop->WatchFileDescriptor(mFd.get(),
   544                                true,
   545                                MessageLoopForIO::WATCH_READ,
   546                                &mReadWatcher,
   547                                this);
   548 }
   550 ssize_t
   551 DroidSocketImpl::ReadMsg(int aFd, void *aBuffer, size_t aLength)
   552 {
   553   ssize_t ret;
   554   struct msghdr msg;
   555   struct iovec iv;
   556   struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
   558   memset(&msg, 0, sizeof(msg));
   559   memset(&iv, 0, sizeof(iv));
   561   iv.iov_base = (unsigned char *)aBuffer;
   562   iv.iov_len = aLength;
   564   msg.msg_iov = &iv;
   565   msg.msg_iovlen = 1;
   566   msg.msg_control = cmsgbuf;
   567   msg.msg_controllen = sizeof(cmsgbuf);
   569   ret = recvmsg(mFd.get(), &msg, MSG_NOSIGNAL);
   570   if (ret < 0 && errno == EPIPE) {
   571     // Treat this as an end of stream
   572     return 0;
   573   }
   575   NS_ENSURE_FALSE(ret < 0, -1);
   576   NS_ENSURE_FALSE(msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE), -1);
   578   // Extract client fd from message header
   579   for (struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg);
   580        cmsgptr != nullptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
   581     if (cmsgptr->cmsg_level != SOL_SOCKET) {
   582       continue;
   583     }
   584     if (cmsgptr->cmsg_type == SCM_RIGHTS) {
   585       int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
   586       // Overwrite fd with client fd
   587       mFd.reset(pDescriptors[0]);
   588       break;
   589     }
   590   }
   592   return ret;
   593 }
   595 void
   596 DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
   597 {
   598   MOZ_ASSERT(!NS_IsMainThread());
   599   MOZ_ASSERT(!mShuttingDownOnIOThread);
   601   // Read all of the incoming data.
   602   while (true) {
   603     nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
   605     ssize_t ret;
   606     if (!mReadMsgForClientFd) {
   607       ret = read(aFd, incoming->mData, incoming->mSize);
   608     } else {
   609       ret = ReadMsg(aFd, incoming->mData, incoming->mSize);
   610     }
   612     if (ret <= 0) {
   613       if (ret == -1) {
   614         if (errno == EINTR) {
   615           continue; // retry system call when interrupted
   616         }
   617         if (errno == EAGAIN || errno == EWOULDBLOCK) {
   618           return; // no data available: return and re-poll
   619         }
   621         BT_WARNING("Cannot read from network");
   622         // else fall through to error handling on other errno's
   623       }
   625       // We're done with our descriptors. Ensure that spurious events don't
   626       // cause us to end up back here.
   627       mReadWatcher.StopWatchingFileDescriptor();
   628       mWriteWatcher.StopWatchingFileDescriptor();
   629       nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
   630       NS_DispatchToMainThread(t);
   631       return;
   632     }
   634     incoming->mSize = ret;
   635     nsRefPtr<SocketReceiveTask> t =
   636       new SocketReceiveTask(this, incoming.forget());
   637     NS_DispatchToMainThread(t);
   639     // If ret is less than MAX_READ_SIZE, there's no
   640     // more data in the socket for us to read now.
   641     if (ret < ssize_t(MAX_READ_SIZE)) {
   642       return;
   643     }
   644   }
   646   MOZ_CRASH("We returned early");
   647 }
   649 void
   650 DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
   651 {
   652   MOZ_ASSERT(!NS_IsMainThread());
   653   MOZ_ASSERT(!mShuttingDownOnIOThread);
   654   MOZ_ASSERT(aFd >= 0);
   656   // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
   657   //
   658   // Otherwise, save the byte position of the next byte to write
   659   // within mCurrentWriteOffset, and request another write when the
   660   // system won't block.
   661   //
   662   while (true) {
   663     UnixSocketRawData* data;
   664     if (mOutgoingQ.IsEmpty()) {
   665       return;
   666     }
   667     data = mOutgoingQ.ElementAt(0);
   668     const uint8_t *toWrite;
   669     toWrite = data->mData;
   671     while (data->mCurrentWriteOffset < data->mSize) {
   672       ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
   673       ssize_t written;
   674       written = write (aFd, toWrite + data->mCurrentWriteOffset,
   675                        write_amount);
   676       if (written > 0) {
   677         data->mCurrentWriteOffset += written;
   678       }
   679       if (written != write_amount) {
   680         break;
   681       }
   682     }
   684     if (data->mCurrentWriteOffset != data->mSize) {
   685       MessageLoopForIO::current()->WatchFileDescriptor(
   686         aFd,
   687         false,
   688         MessageLoopForIO::WATCH_WRITE,
   689         &mWriteWatcher,
   690         this);
   691       return;
   692     }
   693     mOutgoingQ.RemoveElementAt(0);
   694     delete data;
   695   }
   696 }
   698 BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
   699                                  BluetoothSocketType aType,
   700                                  bool aAuth,
   701                                  bool aEncrypt)
   702   : mObserver(aObserver)
   703   , mImpl(nullptr)
   704   , mAuth(aAuth)
   705   , mEncrypt(aEncrypt)
   706   , mReceivedSocketInfoLength(0)
   707 {
   708   MOZ_ASSERT(aObserver);
   710   EnsureBluetoothSocketHalLoad();
   711   mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
   712 }
   714 void
   715 BluetoothSocket::CloseDroidSocket()
   716 {
   717   MOZ_ASSERT(NS_IsMainThread());
   718   if (!mImpl) {
   719     return;
   720   }
   722   // From this point on, we consider mImpl as being deleted.
   723   // We sever the relationship here so any future calls to listen or connect
   724   // will create a new implementation.
   725   mImpl->ShutdownOnMainThread();
   726   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
   727                                    new ShutdownSocketTask(mImpl));
   728   mImpl = nullptr;
   730   OnDisconnect();
   731 }
   733 bool
   734 BluetoothSocket::Connect(const nsAString& aDeviceAddress, int aChannel)
   735 {
   736   MOZ_ASSERT(NS_IsMainThread());
   737   NS_ENSURE_FALSE(mImpl, false);
   739   mIsServer = false;
   740   mImpl = new DroidSocketImpl(this, aDeviceAddress, aChannel, mAuth, mEncrypt);
   741   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
   742                                    new SocketConnectTask(mImpl));
   744   return true;
   745 }
   747 bool
   748 BluetoothSocket::Listen(int aChannel)
   749 {
   750   MOZ_ASSERT(NS_IsMainThread());
   751   NS_ENSURE_FALSE(mImpl, false);
   753   mIsServer = true;
   754   mImpl = new DroidSocketImpl(this, aChannel, mAuth, mEncrypt);
   755   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
   756                                    new SocketListenTask(mImpl));
   757   return true;
   758 }
   760 bool
   761 BluetoothSocket::SendDroidSocketData(UnixSocketRawData* aData)
   762 {
   763   MOZ_ASSERT(NS_IsMainThread());
   764   NS_ENSURE_TRUE(mImpl, false);
   766   MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
   767   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
   768                                    new SocketSendTask(this, mImpl, aData));
   769   return true;
   770 }
   772 bool
   773 BluetoothSocket::ReceiveSocketInfo(nsAutoPtr<UnixSocketRawData>& aMessage)
   774 {
   775   MOZ_ASSERT(NS_IsMainThread());
   777   /**
   778    * 2 socket info messages (20 bytes) to receive at the beginning:
   779    * - 1st message: [channel:4]
   780    * - 2nd message: [size:2][bd address:6][channel:4][connection status:4]
   781    */
   782   if (mReceivedSocketInfoLength >= TOTAL_SOCKET_INFO_LENGTH) {
   783     // We've got both socket info messages
   784     return false;
   785   }
   786   mReceivedSocketInfoLength += aMessage->mSize;
   788   size_t offset = 0;
   789   if (mReceivedSocketInfoLength == FIRST_SOCKET_INFO_MSG_LENGTH) {
   790     // 1st message: [channel:4]
   791     int32_t channel = ReadInt32(aMessage->mData, &offset);
   792     BT_LOGR("channel %d", channel);
   794     // If this is server socket, read header of next message for client fd
   795     mImpl->mReadMsgForClientFd = mIsServer;
   796   } else if (mReceivedSocketInfoLength == TOTAL_SOCKET_INFO_LENGTH) {
   797     // 2nd message: [size:2][bd address:6][channel:4][connection status:4]
   798     int16_t size = ReadInt16(aMessage->mData, &offset);
   799     ReadBdAddress(aMessage->mData, &offset, mDeviceAddress);
   800     int32_t channel = ReadInt32(aMessage->mData, &offset);
   801     int32_t connectionStatus = ReadInt32(aMessage->mData, &offset);
   803     BT_LOGR("size %d channel %d remote addr %s status %d",
   804       size, channel, NS_ConvertUTF16toUTF8(mDeviceAddress).get(), connectionStatus);
   806     if (connectionStatus != 0) {
   807       OnConnectError();
   808       return true;
   809     }
   811     if (mIsServer) {
   812       mImpl->mReadMsgForClientFd = false;
   813       // Connect client fd on IO thread
   814       XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
   815                                        new SocketConnectClientFdTask(mImpl));
   816     }
   817     OnConnectSuccess();
   818   }
   820   return true;
   821 }
   823 void
   824 BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
   825 {
   826   if (ReceiveSocketInfo(aMessage)) {
   827     return;
   828   }
   830   MOZ_ASSERT(NS_IsMainThread());
   831   MOZ_ASSERT(mObserver);
   832   mObserver->ReceiveSocketData(this, aMessage);
   833 }
   835 void
   836 BluetoothSocket::OnConnectSuccess()
   837 {
   838   MOZ_ASSERT(NS_IsMainThread());
   839   MOZ_ASSERT(mObserver);
   840   mObserver->OnSocketConnectSuccess(this);
   841 }
   843 void
   844 BluetoothSocket::OnConnectError()
   845 {
   846   MOZ_ASSERT(NS_IsMainThread());
   847   MOZ_ASSERT(mObserver);
   848   mObserver->OnSocketConnectError(this);
   849 }
   851 void
   852 BluetoothSocket::OnDisconnect()
   853 {
   854   MOZ_ASSERT(NS_IsMainThread());
   855   MOZ_ASSERT(mObserver);
   856   mObserver->OnSocketDisconnect(this);
   857 }

mercurial