mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
672 lines
16 KiB
C++
672 lines
16 KiB
C++
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "BluetoothSocket.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include "base/message_loop.h"
|
|
#include "BluetoothInterface.h"
|
|
#include "BluetoothSocketObserver.h"
|
|
#include "BluetoothUtils.h"
|
|
#include "mozilla/FileUtils.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsXULAppAPI.h"
|
|
|
|
using namespace mozilla::ipc;
|
|
USING_BLUETOOTH_NAMESPACE
|
|
|
|
static const size_t MAX_READ_SIZE = 1 << 16;
|
|
static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
|
|
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
|
|
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
|
|
};
|
|
static BluetoothSocketInterface* sBluetoothSocketInterface;
|
|
|
|
// helper functions
|
|
static bool
|
|
EnsureBluetoothSocketHalLoad()
|
|
{
|
|
if (sBluetoothSocketInterface) {
|
|
return true;
|
|
}
|
|
|
|
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
|
NS_ENSURE_TRUE(btInf, false);
|
|
|
|
sBluetoothSocketInterface = btInf->GetBluetoothSocketInterface();
|
|
NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
class mozilla::dom::bluetooth::DroidSocketImpl : public ipc::UnixFdWatcher
|
|
, protected SocketIOBase
|
|
{
|
|
public:
|
|
/* The connection status in DroidSocketImpl indicates the current
|
|
* phase of the socket connection. The initial settign should always
|
|
* be DISCONNECTED, when no connection is present.
|
|
*
|
|
* To establish a connection on the server, DroidSocketImpl moves
|
|
* to LISTENING. It now waits for incoming connection attempts by
|
|
* installing a read watcher on the I/O thread. When its socket file
|
|
* descriptor becomes readable, DroidSocketImpl accepts the connection
|
|
* and finally moves DroidSocketImpl to CONNECTED. DroidSocketImpl now
|
|
* uses read and write watchers during data transfers. Any socket setup
|
|
* is handled internally by the accept method.
|
|
*
|
|
* On the client side, DroidSocketImpl moves to CONNECTING and installs
|
|
* a write watcher on the I/O thread to wait until the connection is
|
|
* ready. The socket setup is handled internally by the connect method.
|
|
* Installing the write handler makes the code compatible with POSIX
|
|
* semantics for non-blocking connects and gives a clear signal when the
|
|
* conncetion is ready. DroidSocketImpl then moves to CONNECTED and uses
|
|
* read and write watchers during data transfers.
|
|
*/
|
|
enum ConnectionStatus {
|
|
SOCKET_IS_DISCONNECTED = 0,
|
|
SOCKET_IS_LISTENING,
|
|
SOCKET_IS_CONNECTING,
|
|
SOCKET_IS_CONNECTED
|
|
};
|
|
|
|
DroidSocketImpl(MessageLoop* aIOLoop, BluetoothSocket* aConsumer)
|
|
: ipc::UnixFdWatcher(aIOLoop)
|
|
, SocketIOBase(MAX_READ_SIZE)
|
|
, mConsumer(aConsumer)
|
|
, mShuttingDownOnIOThread(false)
|
|
, mConnectionStatus(SOCKET_IS_DISCONNECTED)
|
|
{ }
|
|
|
|
~DroidSocketImpl()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
}
|
|
|
|
void Send(UnixSocketRawData* aData)
|
|
{
|
|
EnqueueData(aData);
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
|
|
bool IsShutdownOnMainThread()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
return mConsumer == nullptr;
|
|
}
|
|
|
|
bool IsShutdownOnIOThread()
|
|
{
|
|
return mShuttingDownOnIOThread;
|
|
}
|
|
|
|
void ShutdownOnMainThread()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(!IsShutdownOnMainThread());
|
|
mConsumer = nullptr;
|
|
}
|
|
|
|
void ShutdownOnIOThread()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
|
|
|
Close(); // will also remove fd from I/O loop
|
|
mShuttingDownOnIOThread = true;
|
|
}
|
|
|
|
void Connect(int aFd);
|
|
void Listen(int aFd);
|
|
void Accept(int aFd);
|
|
|
|
void ConnectClientFd()
|
|
{
|
|
// Stop current read watch
|
|
RemoveWatchers(READ_WATCHER);
|
|
|
|
mConnectionStatus = SOCKET_IS_CONNECTED;
|
|
|
|
// Restart read & write watch on client fd
|
|
AddWatchers(READ_WATCHER, true);
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
|
|
SocketConsumerBase* GetConsumer()
|
|
{
|
|
return mConsumer.get();
|
|
}
|
|
|
|
/**
|
|
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
|
|
* directly from main thread. All non-main-thread accesses should happen with
|
|
* mImpl as container.
|
|
*/
|
|
RefPtr<BluetoothSocket> mConsumer;
|
|
|
|
private:
|
|
/**
|
|
* libevent triggered functions that reads data from socket when available and
|
|
* guarenteed non-blocking. Only to be called on IO thread.
|
|
*
|
|
* @param aFd [in] File descriptor to read from
|
|
*/
|
|
virtual void OnFileCanReadWithoutBlocking(int aFd);
|
|
|
|
/**
|
|
* libevent or developer triggered functions that writes data to socket when
|
|
* available and guarenteed non-blocking. Only to be called on IO thread.
|
|
*
|
|
* @param aFd [in] File descriptor to read from
|
|
*/
|
|
virtual void OnFileCanWriteWithoutBlocking(int aFd);
|
|
|
|
void OnSocketCanReceiveWithoutBlocking(int aFd);
|
|
void OnSocketCanAcceptWithoutBlocking(int aFd);
|
|
void OnSocketCanSendWithoutBlocking(int aFd);
|
|
void OnSocketCanConnectWithoutBlocking(int aFd);
|
|
|
|
/**
|
|
* If true, do not requeue whatever task we're running
|
|
*/
|
|
bool mShuttingDownOnIOThread;
|
|
|
|
ConnectionStatus mConnectionStatus;
|
|
};
|
|
|
|
class SocketConnectTask MOZ_FINAL : public SocketIOTask<DroidSocketImpl>
|
|
{
|
|
public:
|
|
SocketConnectTask(DroidSocketImpl* aDroidSocketImpl, int aFd)
|
|
: SocketIOTask<DroidSocketImpl>(aDroidSocketImpl)
|
|
, mFd(aFd)
|
|
{ }
|
|
|
|
void Run() MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!IsCanceled());
|
|
|
|
GetIO()->Connect(mFd);
|
|
}
|
|
|
|
private:
|
|
int mFd;
|
|
};
|
|
|
|
class SocketListenTask MOZ_FINAL : public SocketIOTask<DroidSocketImpl>
|
|
{
|
|
public:
|
|
SocketListenTask(DroidSocketImpl* aDroidSocketImpl, int aFd)
|
|
: SocketIOTask<DroidSocketImpl>(aDroidSocketImpl)
|
|
, mFd(aFd)
|
|
{ }
|
|
|
|
void Run() MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
if (!IsCanceled()) {
|
|
GetIO()->Listen(mFd);
|
|
}
|
|
}
|
|
|
|
private:
|
|
int mFd;
|
|
};
|
|
|
|
class SocketConnectClientFdTask MOZ_FINAL
|
|
: public SocketIOTask<DroidSocketImpl>
|
|
{
|
|
SocketConnectClientFdTask(DroidSocketImpl* aImpl)
|
|
: SocketIOTask<DroidSocketImpl>(aImpl)
|
|
{ }
|
|
|
|
void Run() MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
GetIO()->ConnectClientFd();
|
|
}
|
|
};
|
|
|
|
void
|
|
DroidSocketImpl::Connect(int aFd)
|
|
{
|
|
MOZ_ASSERT(aFd >= 0);
|
|
|
|
int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
|
|
NS_ENSURE_TRUE_VOID(flags >= 0);
|
|
|
|
if (!(flags & O_NONBLOCK)) {
|
|
int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags | O_NONBLOCK));
|
|
NS_ENSURE_TRUE_VOID(!res);
|
|
}
|
|
|
|
SetFd(aFd);
|
|
mConnectionStatus = SOCKET_IS_CONNECTING;
|
|
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::Listen(int aFd)
|
|
{
|
|
MOZ_ASSERT(aFd >= 0);
|
|
|
|
int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
|
|
NS_ENSURE_TRUE_VOID(flags >= 0);
|
|
|
|
if (!(flags & O_NONBLOCK)) {
|
|
int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags | O_NONBLOCK));
|
|
NS_ENSURE_TRUE_VOID(!res);
|
|
}
|
|
|
|
SetFd(aFd);
|
|
mConnectionStatus = SOCKET_IS_LISTENING;
|
|
|
|
AddWatchers(READ_WATCHER, true);
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::Accept(int aFd)
|
|
{
|
|
Close();
|
|
|
|
int flags = TEMP_FAILURE_RETRY(fcntl(aFd, F_GETFL));
|
|
NS_ENSURE_TRUE_VOID(flags >= 0);
|
|
|
|
if (!(flags & O_NONBLOCK)) {
|
|
int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags | O_NONBLOCK));
|
|
NS_ENSURE_TRUE_VOID(!res);
|
|
}
|
|
|
|
SetFd(aFd);
|
|
mConnectionStatus = SOCKET_IS_CONNECTED;
|
|
|
|
nsRefPtr<nsRunnable> r =
|
|
new SocketIOEventRunnable<DroidSocketImpl>(
|
|
this, SocketIOEventRunnable<DroidSocketImpl>::CONNECT_SUCCESS);
|
|
NS_DispatchToMainThread(r);
|
|
|
|
AddWatchers(READ_WATCHER, true);
|
|
if (HasPendingData()) {
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
|
|
{
|
|
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
|
|
OnSocketCanReceiveWithoutBlocking(aFd);
|
|
} else if (mConnectionStatus == SOCKET_IS_LISTENING) {
|
|
OnSocketCanAcceptWithoutBlocking(aFd);
|
|
} else {
|
|
NS_NOTREACHED("invalid connection state for reading");
|
|
}
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::OnSocketCanReceiveWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
|
|
|
ssize_t res = ReceiveData(aFd, this);
|
|
if (res < 0) {
|
|
/* I/O error */
|
|
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
|
|
} else if (!res) {
|
|
/* EOF or peer shutdown */
|
|
RemoveWatchers(READ_WATCHER);
|
|
}
|
|
}
|
|
|
|
class AcceptTask MOZ_FINAL : public SocketIOTask<DroidSocketImpl>
|
|
{
|
|
public:
|
|
AcceptTask(DroidSocketImpl* aDroidSocketImpl, int aFd)
|
|
: SocketIOTask<DroidSocketImpl>(aDroidSocketImpl)
|
|
, mFd(aFd)
|
|
{ }
|
|
|
|
void Run() MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!IsCanceled());
|
|
|
|
GetIO()->Accept(mFd);
|
|
}
|
|
|
|
private:
|
|
int mFd;
|
|
};
|
|
|
|
class AcceptResultHandler MOZ_FINAL : public BluetoothSocketResultHandler
|
|
{
|
|
public:
|
|
AcceptResultHandler(DroidSocketImpl* aImpl)
|
|
: mImpl(aImpl)
|
|
{
|
|
MOZ_ASSERT(mImpl);
|
|
}
|
|
|
|
void Accept(int aFd, const nsAString& aBdAddress,
|
|
int aConnectionStatus) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (mImpl->IsShutdownOnMainThread()) {
|
|
BT_LOGD("mConsumer is null, aborting receive!");
|
|
return;
|
|
}
|
|
|
|
mImpl->mConsumer->SetAddress(aBdAddress);
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
|
|
}
|
|
|
|
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
|
|
}
|
|
|
|
private:
|
|
DroidSocketImpl* mImpl;
|
|
};
|
|
|
|
class AcceptRunnable MOZ_FINAL : public SocketIORunnable<DroidSocketImpl>
|
|
{
|
|
public:
|
|
AcceptRunnable(DroidSocketImpl* aImpl, int aFd)
|
|
: SocketIORunnable<DroidSocketImpl>(aImpl)
|
|
, mFd(aFd)
|
|
{ }
|
|
|
|
NS_IMETHOD Run() MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(sBluetoothSocketInterface);
|
|
|
|
BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
|
|
GetIO()->mConsumer->SetCurrentResultHandler(res);
|
|
|
|
sBluetoothSocketInterface->Accept(mFd, res);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
int mFd;
|
|
};
|
|
|
|
void
|
|
DroidSocketImpl::OnSocketCanAcceptWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
|
|
|
/* When a listening socket is ready for receiving data,
|
|
* we can call |Accept| on it.
|
|
*/
|
|
|
|
RemoveWatchers(READ_WATCHER);
|
|
nsRefPtr<AcceptRunnable> t = new AcceptRunnable(this, aFd);
|
|
NS_DispatchToMainThread(t);
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
|
|
{
|
|
if (mConnectionStatus == SOCKET_IS_CONNECTED) {
|
|
OnSocketCanSendWithoutBlocking(aFd);
|
|
} else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
|
|
OnSocketCanConnectWithoutBlocking(aFd);
|
|
} else {
|
|
NS_NOTREACHED("invalid connection state for writing");
|
|
}
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::OnSocketCanSendWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
|
MOZ_ASSERT(aFd >= 0);
|
|
|
|
nsresult rv = SendPendingData(aFd, this);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
|
|
if (HasPendingData()) {
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
}
|
|
|
|
void
|
|
DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
|
|
|
/* We follow Posix behaviour here: Connect operations are
|
|
* complete once we can write to the connecting socket.
|
|
*/
|
|
|
|
mConnectionStatus = SOCKET_IS_CONNECTED;
|
|
|
|
nsRefPtr<nsRunnable> r =
|
|
new SocketIOEventRunnable<DroidSocketImpl>(
|
|
this, SocketIOEventRunnable<DroidSocketImpl>::CONNECT_SUCCESS);
|
|
NS_DispatchToMainThread(r);
|
|
|
|
AddWatchers(READ_WATCHER, true);
|
|
if (HasPendingData()) {
|
|
AddWatchers(WRITE_WATCHER, false);
|
|
}
|
|
}
|
|
|
|
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
|
|
BluetoothSocketType aType,
|
|
bool aAuth,
|
|
bool aEncrypt)
|
|
: mObserver(aObserver)
|
|
, mCurrentRes(nullptr)
|
|
, mImpl(nullptr)
|
|
, mAuth(aAuth)
|
|
, mEncrypt(aEncrypt)
|
|
{
|
|
MOZ_ASSERT(aObserver);
|
|
|
|
EnsureBluetoothSocketHalLoad();
|
|
mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
|
|
}
|
|
|
|
class ConnectSocketResultHandler MOZ_FINAL : public BluetoothSocketResultHandler
|
|
{
|
|
public:
|
|
ConnectSocketResultHandler(DroidSocketImpl* aImpl)
|
|
: mImpl(aImpl)
|
|
{
|
|
MOZ_ASSERT(mImpl);
|
|
}
|
|
|
|
void Connect(int aFd, const nsAString& aBdAddress,
|
|
int aConnectionStatus) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!mImpl->IsShutdownOnMainThread()) {
|
|
mImpl->mConsumer->SetAddress(aBdAddress);
|
|
}
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
|
new SocketConnectTask(mImpl, aFd));
|
|
}
|
|
|
|
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
BT_WARNING("Connect failed: %d", (int)aStatus);
|
|
}
|
|
|
|
private:
|
|
DroidSocketImpl* mImpl;
|
|
};
|
|
|
|
bool
|
|
BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
NS_ENSURE_FALSE(mImpl, false);
|
|
|
|
SetConnectionStatus(SOCKET_CONNECTING);
|
|
|
|
mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
|
|
|
|
BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
|
|
SetCurrentResultHandler(res);
|
|
|
|
// TODO: uuid as argument
|
|
sBluetoothSocketInterface->Connect(
|
|
aDeviceAddress,
|
|
BluetoothSocketType::RFCOMM,
|
|
UUID_OBEX_OBJECT_PUSH,
|
|
aChannel, mEncrypt, mAuth, res);
|
|
|
|
return true;
|
|
}
|
|
|
|
class ListenResultHandler MOZ_FINAL : public BluetoothSocketResultHandler
|
|
{
|
|
public:
|
|
ListenResultHandler(DroidSocketImpl* aImpl)
|
|
: mImpl(aImpl)
|
|
{
|
|
MOZ_ASSERT(mImpl);
|
|
}
|
|
|
|
void Listen(int aFd) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
|
new SocketListenTask(mImpl, aFd));
|
|
}
|
|
|
|
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
BT_WARNING("Listen failed: %d", (int)aStatus);
|
|
}
|
|
|
|
private:
|
|
DroidSocketImpl* mImpl;
|
|
};
|
|
|
|
bool
|
|
BluetoothSocket::ListenSocket(int aChannel)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
NS_ENSURE_FALSE(mImpl, false);
|
|
|
|
SetConnectionStatus(SOCKET_LISTENING);
|
|
|
|
mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
|
|
|
|
BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
|
|
SetCurrentResultHandler(res);
|
|
|
|
sBluetoothSocketInterface->Listen(
|
|
BluetoothSocketType::RFCOMM,
|
|
NS_LITERAL_STRING("OBEX Object Push"),
|
|
UUID_OBEX_OBJECT_PUSH,
|
|
aChannel, mEncrypt, mAuth, res);
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BluetoothSocket::CloseSocket()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(sBluetoothSocketInterface);
|
|
if (!mImpl) {
|
|
return;
|
|
}
|
|
|
|
// Stop any watching |SocketMessageWatcher|
|
|
if (mCurrentRes) {
|
|
sBluetoothSocketInterface->Close(mCurrentRes);
|
|
}
|
|
|
|
// From this point on, we consider mImpl as being deleted.
|
|
// We sever the relationship here so any future calls to listen or connect
|
|
// will create a new implementation.
|
|
mImpl->ShutdownOnMainThread();
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE, new SocketIOShutdownTask<DroidSocketImpl>(mImpl));
|
|
|
|
mImpl = nullptr;
|
|
|
|
NotifyDisconnect();
|
|
}
|
|
|
|
bool
|
|
BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
NS_ENSURE_TRUE(mImpl, false);
|
|
|
|
MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE, new SocketIOSendTask<DroidSocketImpl>(mImpl, aData));
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mObserver);
|
|
mObserver->ReceiveSocketData(this, aMessage);
|
|
}
|
|
|
|
void
|
|
BluetoothSocket::OnConnectSuccess()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mObserver);
|
|
|
|
SetCurrentResultHandler(nullptr);
|
|
mObserver->OnSocketConnectSuccess(this);
|
|
}
|
|
|
|
void
|
|
BluetoothSocket::OnConnectError()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mObserver);
|
|
|
|
SetCurrentResultHandler(nullptr);
|
|
mObserver->OnSocketConnectError(this);
|
|
}
|
|
|
|
void
|
|
BluetoothSocket::OnDisconnect()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mObserver);
|
|
mObserver->OnSocketDisconnect(this);
|
|
}
|