1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,858 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "BluetoothSocket.h" 1.11 + 1.12 +#include <hardware/bluetooth.h> 1.13 +#include <hardware/bt_sock.h> 1.14 +#include <sys/socket.h> 1.15 + 1.16 +#include "base/message_loop.h" 1.17 +#include "BluetoothSocketObserver.h" 1.18 +#include "BluetoothUtils.h" 1.19 +#include "mozilla/FileUtils.h" 1.20 +#include "mozilla/RefPtr.h" 1.21 +#include "nsThreadUtils.h" 1.22 +#include "nsXULAppAPI.h" 1.23 + 1.24 +#define FIRST_SOCKET_INFO_MSG_LENGTH 4 1.25 +#define TOTAL_SOCKET_INFO_LENGTH 20 1.26 + 1.27 +using namespace mozilla::ipc; 1.28 +USING_BLUETOOTH_NAMESPACE 1.29 + 1.30 +static const size_t MAX_READ_SIZE = 1 << 16; 1.31 +static const uint8_t UUID_OBEX_OBJECT_PUSH[] = { 1.32 + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00, 1.33 + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB 1.34 +}; 1.35 +static const btsock_interface_t* sBluetoothSocketInterface = nullptr; 1.36 + 1.37 +// helper functions 1.38 +static bool 1.39 +EnsureBluetoothSocketHalLoad() 1.40 +{ 1.41 + if (sBluetoothSocketInterface) { 1.42 + return true; 1.43 + } 1.44 + 1.45 + const bt_interface_t* btInf = GetBluetoothInterface(); 1.46 + NS_ENSURE_TRUE(btInf, false); 1.47 + 1.48 + sBluetoothSocketInterface = 1.49 + (btsock_interface_t *) btInf->get_profile_interface(BT_PROFILE_SOCKETS_ID); 1.50 + NS_ENSURE_TRUE(sBluetoothSocketInterface, false); 1.51 + 1.52 + return true; 1.53 +} 1.54 + 1.55 +static int16_t 1.56 +ReadInt16(const uint8_t* aData, size_t* aOffset) 1.57 +{ 1.58 + int16_t value = (aData[*aOffset + 1] << 8) | aData[*aOffset]; 1.59 + 1.60 + *aOffset += 2; 1.61 + return value; 1.62 +} 1.63 + 1.64 +static int32_t 1.65 +ReadInt32(const uint8_t* aData, size_t* aOffset) 1.66 +{ 1.67 + int32_t value = (aData[*aOffset + 3] << 24) | 1.68 + (aData[*aOffset + 2] << 16) | 1.69 + (aData[*aOffset + 1] << 8) | 1.70 + aData[*aOffset]; 1.71 + *aOffset += 4; 1.72 + return value; 1.73 +} 1.74 + 1.75 +static void 1.76 +ReadBdAddress(const uint8_t* aData, size_t* aOffset, nsAString& aDeviceAddress) 1.77 +{ 1.78 + char bdstr[18]; 1.79 + sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x", 1.80 + aData[*aOffset], aData[*aOffset + 1], aData[*aOffset + 2], 1.81 + aData[*aOffset + 3], aData[*aOffset + 4], aData[*aOffset + 5]); 1.82 + 1.83 + aDeviceAddress.AssignLiteral(bdstr); 1.84 + *aOffset += 6; 1.85 +} 1.86 + 1.87 +class mozilla::dom::bluetooth::DroidSocketImpl 1.88 + : public MessageLoopForIO::Watcher 1.89 +{ 1.90 +public: 1.91 + DroidSocketImpl(BluetoothSocket* aConsumer, int aFd) 1.92 + : mConsumer(aConsumer) 1.93 + , mReadMsgForClientFd(false) 1.94 + , mIOLoop(nullptr) 1.95 + , mFd(aFd) 1.96 + , mShuttingDownOnIOThread(false) 1.97 + , mChannel(0) 1.98 + , mAuth(false) 1.99 + , mEncrypt(false) 1.100 + { 1.101 + } 1.102 + 1.103 + DroidSocketImpl(BluetoothSocket* aConsumer, 1.104 + int aChannel, bool aAuth, bool aEncrypt) 1.105 + : mConsumer(aConsumer) 1.106 + , mReadMsgForClientFd(false) 1.107 + , mIOLoop(nullptr) 1.108 + , mFd(-1) 1.109 + , mShuttingDownOnIOThread(false) 1.110 + , mChannel(aChannel) 1.111 + , mAuth(aAuth) 1.112 + , mEncrypt(aEncrypt) 1.113 + { } 1.114 + 1.115 + DroidSocketImpl(BluetoothSocket* aConsumer, const nsAString& aDeviceAddress, 1.116 + int aChannel, bool aAuth, bool aEncrypt) 1.117 + : mConsumer(aConsumer) 1.118 + , mReadMsgForClientFd(false) 1.119 + , mIOLoop(nullptr) 1.120 + , mFd(-1) 1.121 + , mShuttingDownOnIOThread(false) 1.122 + , mDeviceAddress(aDeviceAddress) 1.123 + , mChannel(aChannel) 1.124 + , mAuth(aAuth) 1.125 + , mEncrypt(aEncrypt) 1.126 + { 1.127 + MOZ_ASSERT(!mDeviceAddress.IsEmpty()); 1.128 + } 1.129 + 1.130 + ~DroidSocketImpl() 1.131 + { 1.132 + MOZ_ASSERT(NS_IsMainThread()); 1.133 + } 1.134 + 1.135 + void QueueWriteData(UnixSocketRawData* aData) 1.136 + { 1.137 + mOutgoingQ.AppendElement(aData); 1.138 + OnFileCanWriteWithoutBlocking(mFd); 1.139 + } 1.140 + 1.141 + bool IsShutdownOnMainThread() 1.142 + { 1.143 + MOZ_ASSERT(NS_IsMainThread()); 1.144 + return mConsumer == nullptr; 1.145 + } 1.146 + 1.147 + bool IsShutdownOnIOThread() 1.148 + { 1.149 + return mShuttingDownOnIOThread; 1.150 + } 1.151 + 1.152 + void ShutdownOnMainThread() 1.153 + { 1.154 + MOZ_ASSERT(NS_IsMainThread()); 1.155 + MOZ_ASSERT(!IsShutdownOnMainThread()); 1.156 + mConsumer = nullptr; 1.157 + } 1.158 + 1.159 + void ShutdownOnIOThread() 1.160 + { 1.161 + MOZ_ASSERT(!NS_IsMainThread()); 1.162 + MOZ_ASSERT(!mShuttingDownOnIOThread); 1.163 + 1.164 + mReadWatcher.StopWatchingFileDescriptor(); 1.165 + mWriteWatcher.StopWatchingFileDescriptor(); 1.166 + 1.167 + mShuttingDownOnIOThread = true; 1.168 + } 1.169 + 1.170 + void Connect(); 1.171 + void Listen(); 1.172 + 1.173 + void SetUpIO(bool aWrite) 1.174 + { 1.175 + MOZ_ASSERT(!mIOLoop); 1.176 + MOZ_ASSERT(mFd >= 0); 1.177 + mIOLoop = MessageLoopForIO::current(); 1.178 + 1.179 + // Set up a read watch 1.180 + mIOLoop->WatchFileDescriptor(mFd, 1.181 + true, 1.182 + MessageLoopForIO::WATCH_READ, 1.183 + &mReadWatcher, 1.184 + this); 1.185 + 1.186 + if (aWrite) { 1.187 + // Set up a write watch 1.188 + mIOLoop->WatchFileDescriptor(mFd.get(), 1.189 + false, 1.190 + MessageLoopForIO::WATCH_WRITE, 1.191 + &mWriteWatcher, 1.192 + this); 1.193 + } 1.194 + } 1.195 + 1.196 + void ConnectClientFd() 1.197 + { 1.198 + // Stop current read watch 1.199 + mReadWatcher.StopWatchingFileDescriptor(); 1.200 + mIOLoop = nullptr; 1.201 + 1.202 + // Restart read & write watch on client fd 1.203 + SetUpIO(true); 1.204 + } 1.205 + 1.206 + /** 1.207 + * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated 1.208 + * directly from main thread. All non-main-thread accesses should happen with 1.209 + * mImpl as container. 1.210 + */ 1.211 + RefPtr<BluetoothSocket> mConsumer; 1.212 + 1.213 + /** 1.214 + * If true, read message header to get client fd. 1.215 + */ 1.216 + bool mReadMsgForClientFd; 1.217 + 1.218 +private: 1.219 + /** 1.220 + * libevent triggered functions that reads data from socket when available and 1.221 + * guarenteed non-blocking. Only to be called on IO thread. 1.222 + * 1.223 + * @param aFd [in] File descriptor to read from 1.224 + */ 1.225 + virtual void OnFileCanReadWithoutBlocking(int aFd); 1.226 + 1.227 + /** 1.228 + * libevent or developer triggered functions that writes data to socket when 1.229 + * available and guarenteed non-blocking. Only to be called on IO thread. 1.230 + * 1.231 + * @param aFd [in] File descriptor to read from 1.232 + */ 1.233 + virtual void OnFileCanWriteWithoutBlocking(int aFd); 1.234 + 1.235 + /** 1.236 + * Read message to get data and client fd wrapped in message header 1.237 + * 1.238 + * @param aFd [in] File descriptor to read message from 1.239 + * @param aBuffer [out] Data buffer read 1.240 + * @param aLength [out] Number of bytes read 1.241 + */ 1.242 + ssize_t ReadMsg(int aFd, void *aBuffer, size_t aLength); 1.243 + 1.244 + /** 1.245 + * IO Loop pointer. Must be initalized and called from IO thread only. 1.246 + */ 1.247 + MessageLoopForIO* mIOLoop; 1.248 + 1.249 + /** 1.250 + * Raw data queue. Must be pushed/popped from IO thread only. 1.251 + */ 1.252 + typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue; 1.253 + UnixSocketRawDataQueue mOutgoingQ; 1.254 + 1.255 + /** 1.256 + * Read watcher for libevent. Only to be accessed on IO Thread. 1.257 + */ 1.258 + MessageLoopForIO::FileDescriptorWatcher mReadWatcher; 1.259 + 1.260 + /** 1.261 + * Write watcher for libevent. Only to be accessed on IO Thread. 1.262 + */ 1.263 + MessageLoopForIO::FileDescriptorWatcher mWriteWatcher; 1.264 + 1.265 + /** 1.266 + * File descriptor to read from/write to. Connection happens on user provided 1.267 + * thread. Read/write/close happens on IO thread. 1.268 + */ 1.269 + mozilla::ScopedClose mFd; 1.270 + 1.271 + /** 1.272 + * If true, do not requeue whatever task we're running 1.273 + */ 1.274 + bool mShuttingDownOnIOThread; 1.275 + 1.276 + nsString mDeviceAddress; 1.277 + int mChannel; 1.278 + bool mAuth; 1.279 + bool mEncrypt; 1.280 +}; 1.281 + 1.282 +template<class T> 1.283 +class DeleteInstanceRunnable : public nsRunnable 1.284 +{ 1.285 +public: 1.286 + DeleteInstanceRunnable(T* aInstance) 1.287 + : mInstance(aInstance) 1.288 + { } 1.289 + 1.290 + NS_IMETHOD Run() 1.291 + { 1.292 + delete mInstance; 1.293 + 1.294 + return NS_OK; 1.295 + } 1.296 + 1.297 +private: 1.298 + T* mInstance; 1.299 +}; 1.300 + 1.301 +class RequestClosingSocketTask : public nsRunnable 1.302 +{ 1.303 +public: 1.304 + RequestClosingSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl) 1.305 + { 1.306 + MOZ_ASSERT(aImpl); 1.307 + } 1.308 + 1.309 + NS_IMETHOD Run() 1.310 + { 1.311 + MOZ_ASSERT(NS_IsMainThread()); 1.312 + 1.313 + if (mImpl->IsShutdownOnMainThread()) { 1.314 + NS_WARNING("CloseSocket has already been called!"); 1.315 + // Since we've already explicitly closed and the close happened before 1.316 + // this, this isn't really an error. Since we've warned, return OK. 1.317 + return NS_OK; 1.318 + } 1.319 + 1.320 + // Start from here, same handling flow as calling CloseSocket() from 1.321 + // upper layer 1.322 + mImpl->mConsumer->CloseDroidSocket(); 1.323 + return NS_OK; 1.324 + } 1.325 +private: 1.326 + DroidSocketImpl* mImpl; 1.327 +}; 1.328 + 1.329 +class ShutdownSocketTask : public Task { 1.330 + virtual void Run() 1.331 + { 1.332 + MOZ_ASSERT(!NS_IsMainThread()); 1.333 + 1.334 + // At this point, there should be no new events on the IO thread after this 1.335 + // one with the possible exception of a SocketAcceptTask that 1.336 + // ShutdownOnIOThread will cancel for us. We are now fully shut down, so we 1.337 + // can send a message to the main thread that will delete mImpl safely knowing 1.338 + // that no more tasks reference it. 1.339 + mImpl->ShutdownOnIOThread(); 1.340 + 1.341 + nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable< 1.342 + mozilla::dom::bluetooth::DroidSocketImpl>(mImpl)); 1.343 + nsresult rv = NS_DispatchToMainThread(t); 1.344 + NS_ENSURE_SUCCESS_VOID(rv); 1.345 + } 1.346 + 1.347 + DroidSocketImpl* mImpl; 1.348 + 1.349 +public: 1.350 + ShutdownSocketTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { } 1.351 +}; 1.352 + 1.353 +class SocketReceiveTask : public nsRunnable 1.354 +{ 1.355 +public: 1.356 + SocketReceiveTask(DroidSocketImpl* aImpl, UnixSocketRawData* aData) : 1.357 + mImpl(aImpl), 1.358 + mRawData(aData) 1.359 + { 1.360 + MOZ_ASSERT(aImpl); 1.361 + MOZ_ASSERT(aData); 1.362 + } 1.363 + 1.364 + NS_IMETHOD Run() 1.365 + { 1.366 + MOZ_ASSERT(NS_IsMainThread()); 1.367 + if (mImpl->IsShutdownOnMainThread()) { 1.368 + NS_WARNING("mConsumer is null, aborting receive!"); 1.369 + // Since we've already explicitly closed and the close happened before 1.370 + // this, this isn't really an error. Since we've warned, return OK. 1.371 + return NS_OK; 1.372 + } 1.373 + 1.374 + MOZ_ASSERT(mImpl->mConsumer); 1.375 + mImpl->mConsumer->ReceiveSocketData(mRawData); 1.376 + return NS_OK; 1.377 + } 1.378 +private: 1.379 + DroidSocketImpl* mImpl; 1.380 + nsAutoPtr<UnixSocketRawData> mRawData; 1.381 +}; 1.382 + 1.383 +class SocketSendTask : public Task 1.384 +{ 1.385 +public: 1.386 + SocketSendTask(BluetoothSocket* aConsumer, DroidSocketImpl* aImpl, 1.387 + UnixSocketRawData* aData) 1.388 + : mConsumer(aConsumer), 1.389 + mImpl(aImpl), 1.390 + mData(aData) 1.391 + { 1.392 + MOZ_ASSERT(aConsumer); 1.393 + MOZ_ASSERT(aImpl); 1.394 + MOZ_ASSERT(aData); 1.395 + } 1.396 + 1.397 + void 1.398 + Run() 1.399 + { 1.400 + MOZ_ASSERT(!NS_IsMainThread()); 1.401 + MOZ_ASSERT(!mImpl->IsShutdownOnIOThread()); 1.402 + 1.403 + mImpl->QueueWriteData(mData); 1.404 + } 1.405 + 1.406 +private: 1.407 + nsRefPtr<BluetoothSocket> mConsumer; 1.408 + DroidSocketImpl* mImpl; 1.409 + UnixSocketRawData* mData; 1.410 +}; 1.411 + 1.412 +class DroidSocketImplTask : public CancelableTask 1.413 +{ 1.414 +public: 1.415 + DroidSocketImpl* GetDroidSocketImpl() const 1.416 + { 1.417 + return mDroidSocketImpl; 1.418 + } 1.419 + void Cancel() MOZ_OVERRIDE 1.420 + { 1.421 + mDroidSocketImpl = nullptr; 1.422 + } 1.423 + bool IsCanceled() const 1.424 + { 1.425 + return !mDroidSocketImpl; 1.426 + } 1.427 +protected: 1.428 + DroidSocketImplTask(DroidSocketImpl* aDroidSocketImpl) 1.429 + : mDroidSocketImpl(aDroidSocketImpl) 1.430 + { 1.431 + MOZ_ASSERT(mDroidSocketImpl); 1.432 + } 1.433 +private: 1.434 + DroidSocketImpl* mDroidSocketImpl; 1.435 +}; 1.436 + 1.437 +class SocketConnectTask : public DroidSocketImplTask 1.438 +{ 1.439 +public: 1.440 + SocketConnectTask(DroidSocketImpl* aDroidSocketImpl) 1.441 + : DroidSocketImplTask(aDroidSocketImpl) 1.442 + { } 1.443 + 1.444 + void Run() MOZ_OVERRIDE 1.445 + { 1.446 + MOZ_ASSERT(!NS_IsMainThread()); 1.447 + MOZ_ASSERT(!IsCanceled()); 1.448 + GetDroidSocketImpl()->Connect(); 1.449 + } 1.450 +}; 1.451 + 1.452 +class SocketListenTask : public DroidSocketImplTask 1.453 +{ 1.454 +public: 1.455 + SocketListenTask(DroidSocketImpl* aDroidSocketImpl) 1.456 + : DroidSocketImplTask(aDroidSocketImpl) 1.457 + { } 1.458 + 1.459 + void Run() MOZ_OVERRIDE 1.460 + { 1.461 + MOZ_ASSERT(!NS_IsMainThread()); 1.462 + if (!IsCanceled()) { 1.463 + GetDroidSocketImpl()->Listen(); 1.464 + } 1.465 + } 1.466 +}; 1.467 + 1.468 +class SocketConnectClientFdTask : public Task 1.469 +{ 1.470 + virtual void Run() 1.471 + { 1.472 + MOZ_ASSERT(!NS_IsMainThread()); 1.473 + mImpl->ConnectClientFd(); 1.474 + } 1.475 + 1.476 + DroidSocketImpl* mImpl; 1.477 +public: 1.478 + SocketConnectClientFdTask(DroidSocketImpl* aImpl) : mImpl(aImpl) { } 1.479 +}; 1.480 + 1.481 +void 1.482 +DroidSocketImpl::Connect() 1.483 +{ 1.484 + MOZ_ASSERT(sBluetoothSocketInterface); 1.485 + 1.486 + bt_bdaddr_t remoteBdAddress; 1.487 + StringToBdAddressType(mDeviceAddress, &remoteBdAddress); 1.488 + 1.489 + // TODO: uuid as argument 1.490 + int fd = -1; 1.491 + bt_status_t status = 1.492 + sBluetoothSocketInterface->connect(&remoteBdAddress, 1.493 + BTSOCK_RFCOMM, 1.494 + UUID_OBEX_OBJECT_PUSH, 1.495 + mChannel, 1.496 + &fd, 1.497 + (BTSOCK_FLAG_ENCRYPT * mEncrypt) | 1.498 + (BTSOCK_FLAG_AUTH * mAuth)); 1.499 + NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS); 1.500 + NS_ENSURE_TRUE_VOID(fd >= 0); 1.501 + 1.502 + mFd = fd; 1.503 + 1.504 + MOZ_ASSERT(!mIOLoop); 1.505 + mIOLoop = MessageLoopForIO::current(); 1.506 + 1.507 + // Set up a read watch 1.508 + mIOLoop->WatchFileDescriptor(mFd.get(), 1.509 + true, 1.510 + MessageLoopForIO::WATCH_READ, 1.511 + &mReadWatcher, 1.512 + this); 1.513 + // Set up a write watch 1.514 + mIOLoop->WatchFileDescriptor(mFd.get(), 1.515 + false, 1.516 + MessageLoopForIO::WATCH_WRITE, 1.517 + &mWriteWatcher, 1.518 + this); 1.519 +} 1.520 + 1.521 +void 1.522 +DroidSocketImpl::Listen() 1.523 +{ 1.524 + MOZ_ASSERT(sBluetoothSocketInterface); 1.525 + 1.526 + // TODO: uuid and service name as arguments 1.527 + 1.528 + int fd = -1; 1.529 + bt_status_t status = 1.530 + sBluetoothSocketInterface->listen(BTSOCK_RFCOMM, 1.531 + "OBEX Object Push", 1.532 + UUID_OBEX_OBJECT_PUSH, 1.533 + mChannel, 1.534 + &fd, 1.535 + (BTSOCK_FLAG_ENCRYPT * mEncrypt) | 1.536 + (BTSOCK_FLAG_AUTH * mAuth)); 1.537 + NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS); 1.538 + NS_ENSURE_TRUE_VOID(fd >= 0); 1.539 + 1.540 + mFd = fd; 1.541 + 1.542 + MOZ_ASSERT(!mIOLoop); 1.543 + mIOLoop = MessageLoopForIO::current(); 1.544 + 1.545 + // Set up a read watch 1.546 + mIOLoop->WatchFileDescriptor(mFd.get(), 1.547 + true, 1.548 + MessageLoopForIO::WATCH_READ, 1.549 + &mReadWatcher, 1.550 + this); 1.551 +} 1.552 + 1.553 +ssize_t 1.554 +DroidSocketImpl::ReadMsg(int aFd, void *aBuffer, size_t aLength) 1.555 +{ 1.556 + ssize_t ret; 1.557 + struct msghdr msg; 1.558 + struct iovec iv; 1.559 + struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100]; 1.560 + 1.561 + memset(&msg, 0, sizeof(msg)); 1.562 + memset(&iv, 0, sizeof(iv)); 1.563 + 1.564 + iv.iov_base = (unsigned char *)aBuffer; 1.565 + iv.iov_len = aLength; 1.566 + 1.567 + msg.msg_iov = &iv; 1.568 + msg.msg_iovlen = 1; 1.569 + msg.msg_control = cmsgbuf; 1.570 + msg.msg_controllen = sizeof(cmsgbuf); 1.571 + 1.572 + ret = recvmsg(mFd.get(), &msg, MSG_NOSIGNAL); 1.573 + if (ret < 0 && errno == EPIPE) { 1.574 + // Treat this as an end of stream 1.575 + return 0; 1.576 + } 1.577 + 1.578 + NS_ENSURE_FALSE(ret < 0, -1); 1.579 + NS_ENSURE_FALSE(msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE), -1); 1.580 + 1.581 + // Extract client fd from message header 1.582 + for (struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg); 1.583 + cmsgptr != nullptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { 1.584 + if (cmsgptr->cmsg_level != SOL_SOCKET) { 1.585 + continue; 1.586 + } 1.587 + if (cmsgptr->cmsg_type == SCM_RIGHTS) { 1.588 + int *pDescriptors = (int *)CMSG_DATA(cmsgptr); 1.589 + // Overwrite fd with client fd 1.590 + mFd.reset(pDescriptors[0]); 1.591 + break; 1.592 + } 1.593 + } 1.594 + 1.595 + return ret; 1.596 +} 1.597 + 1.598 +void 1.599 +DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd) 1.600 +{ 1.601 + MOZ_ASSERT(!NS_IsMainThread()); 1.602 + MOZ_ASSERT(!mShuttingDownOnIOThread); 1.603 + 1.604 + // Read all of the incoming data. 1.605 + while (true) { 1.606 + nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE)); 1.607 + 1.608 + ssize_t ret; 1.609 + if (!mReadMsgForClientFd) { 1.610 + ret = read(aFd, incoming->mData, incoming->mSize); 1.611 + } else { 1.612 + ret = ReadMsg(aFd, incoming->mData, incoming->mSize); 1.613 + } 1.614 + 1.615 + if (ret <= 0) { 1.616 + if (ret == -1) { 1.617 + if (errno == EINTR) { 1.618 + continue; // retry system call when interrupted 1.619 + } 1.620 + if (errno == EAGAIN || errno == EWOULDBLOCK) { 1.621 + return; // no data available: return and re-poll 1.622 + } 1.623 + 1.624 + BT_WARNING("Cannot read from network"); 1.625 + // else fall through to error handling on other errno's 1.626 + } 1.627 + 1.628 + // We're done with our descriptors. Ensure that spurious events don't 1.629 + // cause us to end up back here. 1.630 + mReadWatcher.StopWatchingFileDescriptor(); 1.631 + mWriteWatcher.StopWatchingFileDescriptor(); 1.632 + nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this); 1.633 + NS_DispatchToMainThread(t); 1.634 + return; 1.635 + } 1.636 + 1.637 + incoming->mSize = ret; 1.638 + nsRefPtr<SocketReceiveTask> t = 1.639 + new SocketReceiveTask(this, incoming.forget()); 1.640 + NS_DispatchToMainThread(t); 1.641 + 1.642 + // If ret is less than MAX_READ_SIZE, there's no 1.643 + // more data in the socket for us to read now. 1.644 + if (ret < ssize_t(MAX_READ_SIZE)) { 1.645 + return; 1.646 + } 1.647 + } 1.648 + 1.649 + MOZ_CRASH("We returned early"); 1.650 +} 1.651 + 1.652 +void 1.653 +DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd) 1.654 +{ 1.655 + MOZ_ASSERT(!NS_IsMainThread()); 1.656 + MOZ_ASSERT(!mShuttingDownOnIOThread); 1.657 + MOZ_ASSERT(aFd >= 0); 1.658 + 1.659 + // Try to write the bytes of mCurrentRilRawData. If all were written, continue. 1.660 + // 1.661 + // Otherwise, save the byte position of the next byte to write 1.662 + // within mCurrentWriteOffset, and request another write when the 1.663 + // system won't block. 1.664 + // 1.665 + while (true) { 1.666 + UnixSocketRawData* data; 1.667 + if (mOutgoingQ.IsEmpty()) { 1.668 + return; 1.669 + } 1.670 + data = mOutgoingQ.ElementAt(0); 1.671 + const uint8_t *toWrite; 1.672 + toWrite = data->mData; 1.673 + 1.674 + while (data->mCurrentWriteOffset < data->mSize) { 1.675 + ssize_t write_amount = data->mSize - data->mCurrentWriteOffset; 1.676 + ssize_t written; 1.677 + written = write (aFd, toWrite + data->mCurrentWriteOffset, 1.678 + write_amount); 1.679 + if (written > 0) { 1.680 + data->mCurrentWriteOffset += written; 1.681 + } 1.682 + if (written != write_amount) { 1.683 + break; 1.684 + } 1.685 + } 1.686 + 1.687 + if (data->mCurrentWriteOffset != data->mSize) { 1.688 + MessageLoopForIO::current()->WatchFileDescriptor( 1.689 + aFd, 1.690 + false, 1.691 + MessageLoopForIO::WATCH_WRITE, 1.692 + &mWriteWatcher, 1.693 + this); 1.694 + return; 1.695 + } 1.696 + mOutgoingQ.RemoveElementAt(0); 1.697 + delete data; 1.698 + } 1.699 +} 1.700 + 1.701 +BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver, 1.702 + BluetoothSocketType aType, 1.703 + bool aAuth, 1.704 + bool aEncrypt) 1.705 + : mObserver(aObserver) 1.706 + , mImpl(nullptr) 1.707 + , mAuth(aAuth) 1.708 + , mEncrypt(aEncrypt) 1.709 + , mReceivedSocketInfoLength(0) 1.710 +{ 1.711 + MOZ_ASSERT(aObserver); 1.712 + 1.713 + EnsureBluetoothSocketHalLoad(); 1.714 + mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE); 1.715 +} 1.716 + 1.717 +void 1.718 +BluetoothSocket::CloseDroidSocket() 1.719 +{ 1.720 + MOZ_ASSERT(NS_IsMainThread()); 1.721 + if (!mImpl) { 1.722 + return; 1.723 + } 1.724 + 1.725 + // From this point on, we consider mImpl as being deleted. 1.726 + // We sever the relationship here so any future calls to listen or connect 1.727 + // will create a new implementation. 1.728 + mImpl->ShutdownOnMainThread(); 1.729 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.730 + new ShutdownSocketTask(mImpl)); 1.731 + mImpl = nullptr; 1.732 + 1.733 + OnDisconnect(); 1.734 +} 1.735 + 1.736 +bool 1.737 +BluetoothSocket::Connect(const nsAString& aDeviceAddress, int aChannel) 1.738 +{ 1.739 + MOZ_ASSERT(NS_IsMainThread()); 1.740 + NS_ENSURE_FALSE(mImpl, false); 1.741 + 1.742 + mIsServer = false; 1.743 + mImpl = new DroidSocketImpl(this, aDeviceAddress, aChannel, mAuth, mEncrypt); 1.744 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.745 + new SocketConnectTask(mImpl)); 1.746 + 1.747 + return true; 1.748 +} 1.749 + 1.750 +bool 1.751 +BluetoothSocket::Listen(int aChannel) 1.752 +{ 1.753 + MOZ_ASSERT(NS_IsMainThread()); 1.754 + NS_ENSURE_FALSE(mImpl, false); 1.755 + 1.756 + mIsServer = true; 1.757 + mImpl = new DroidSocketImpl(this, aChannel, mAuth, mEncrypt); 1.758 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.759 + new SocketListenTask(mImpl)); 1.760 + return true; 1.761 +} 1.762 + 1.763 +bool 1.764 +BluetoothSocket::SendDroidSocketData(UnixSocketRawData* aData) 1.765 +{ 1.766 + MOZ_ASSERT(NS_IsMainThread()); 1.767 + NS_ENSURE_TRUE(mImpl, false); 1.768 + 1.769 + MOZ_ASSERT(!mImpl->IsShutdownOnMainThread()); 1.770 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.771 + new SocketSendTask(this, mImpl, aData)); 1.772 + return true; 1.773 +} 1.774 + 1.775 +bool 1.776 +BluetoothSocket::ReceiveSocketInfo(nsAutoPtr<UnixSocketRawData>& aMessage) 1.777 +{ 1.778 + MOZ_ASSERT(NS_IsMainThread()); 1.779 + 1.780 + /** 1.781 + * 2 socket info messages (20 bytes) to receive at the beginning: 1.782 + * - 1st message: [channel:4] 1.783 + * - 2nd message: [size:2][bd address:6][channel:4][connection status:4] 1.784 + */ 1.785 + if (mReceivedSocketInfoLength >= TOTAL_SOCKET_INFO_LENGTH) { 1.786 + // We've got both socket info messages 1.787 + return false; 1.788 + } 1.789 + mReceivedSocketInfoLength += aMessage->mSize; 1.790 + 1.791 + size_t offset = 0; 1.792 + if (mReceivedSocketInfoLength == FIRST_SOCKET_INFO_MSG_LENGTH) { 1.793 + // 1st message: [channel:4] 1.794 + int32_t channel = ReadInt32(aMessage->mData, &offset); 1.795 + BT_LOGR("channel %d", channel); 1.796 + 1.797 + // If this is server socket, read header of next message for client fd 1.798 + mImpl->mReadMsgForClientFd = mIsServer; 1.799 + } else if (mReceivedSocketInfoLength == TOTAL_SOCKET_INFO_LENGTH) { 1.800 + // 2nd message: [size:2][bd address:6][channel:4][connection status:4] 1.801 + int16_t size = ReadInt16(aMessage->mData, &offset); 1.802 + ReadBdAddress(aMessage->mData, &offset, mDeviceAddress); 1.803 + int32_t channel = ReadInt32(aMessage->mData, &offset); 1.804 + int32_t connectionStatus = ReadInt32(aMessage->mData, &offset); 1.805 + 1.806 + BT_LOGR("size %d channel %d remote addr %s status %d", 1.807 + size, channel, NS_ConvertUTF16toUTF8(mDeviceAddress).get(), connectionStatus); 1.808 + 1.809 + if (connectionStatus != 0) { 1.810 + OnConnectError(); 1.811 + return true; 1.812 + } 1.813 + 1.814 + if (mIsServer) { 1.815 + mImpl->mReadMsgForClientFd = false; 1.816 + // Connect client fd on IO thread 1.817 + XRE_GetIOMessageLoop()->PostTask(FROM_HERE, 1.818 + new SocketConnectClientFdTask(mImpl)); 1.819 + } 1.820 + OnConnectSuccess(); 1.821 + } 1.822 + 1.823 + return true; 1.824 +} 1.825 + 1.826 +void 1.827 +BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) 1.828 +{ 1.829 + if (ReceiveSocketInfo(aMessage)) { 1.830 + return; 1.831 + } 1.832 + 1.833 + MOZ_ASSERT(NS_IsMainThread()); 1.834 + MOZ_ASSERT(mObserver); 1.835 + mObserver->ReceiveSocketData(this, aMessage); 1.836 +} 1.837 + 1.838 +void 1.839 +BluetoothSocket::OnConnectSuccess() 1.840 +{ 1.841 + MOZ_ASSERT(NS_IsMainThread()); 1.842 + MOZ_ASSERT(mObserver); 1.843 + mObserver->OnSocketConnectSuccess(this); 1.844 +} 1.845 + 1.846 +void 1.847 +BluetoothSocket::OnConnectError() 1.848 +{ 1.849 + MOZ_ASSERT(NS_IsMainThread()); 1.850 + MOZ_ASSERT(mObserver); 1.851 + mObserver->OnSocketConnectError(this); 1.852 +} 1.853 + 1.854 +void 1.855 +BluetoothSocket::OnDisconnect() 1.856 +{ 1.857 + MOZ_ASSERT(NS_IsMainThread()); 1.858 + MOZ_ASSERT(mObserver); 1.859 + mObserver->OnSocketDisconnect(this); 1.860 +} 1.861 +