Thu, 22 Jan 2015 13:21:57 +0100
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 }