зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1036977: Handle socket setup for |Connect| in BluetoothInterface (under bluetooth2/), r=btian
Bluedroid's internal socket setup transfers 2 messages and possibly a file descriptor as the first data of a socket connection. This patch moves the socket-setup code for the |Connect| call to the implementation of BluetoothInterface. BluetoothSocket only handles the socket setup of |Listen|, and general socket state.
This commit is contained in:
Родитель
e0c157ebb2
Коммит
14b9c49fb9
|
@ -4,9 +4,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "base/message_loop.h"
|
||||||
#include "BluetoothInterface.h"
|
#include "BluetoothInterface.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
#include "nsXULAppAPI.h"
|
||||||
|
|
||||||
BEGIN_BLUETOOTH_NAMESPACE
|
BEGIN_BLUETOOTH_NAMESPACE
|
||||||
|
|
||||||
|
@ -69,6 +74,40 @@ private:
|
||||||
Arg1 mArg1;
|
Arg1 mArg1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Obj, typename Res,
|
||||||
|
typename Arg1, typename Arg2, typename Arg3>
|
||||||
|
class BluetoothInterfaceRunnable3 : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BluetoothInterfaceRunnable3(Obj* aObj,
|
||||||
|
Res (Obj::*aMethod)(Arg1, Arg2, Arg3),
|
||||||
|
const Arg1& aArg1, const Arg2& aArg2,
|
||||||
|
const Arg3& aArg3)
|
||||||
|
: mObj(aObj)
|
||||||
|
, mMethod(aMethod)
|
||||||
|
, mArg1(aArg1)
|
||||||
|
, mArg2(aArg2)
|
||||||
|
, mArg3(aArg3)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mObj);
|
||||||
|
MOZ_ASSERT(mMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_METHOD
|
||||||
|
Run() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
((*mObj).*mMethod)(mArg1, mArg2, mArg3);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<Obj> mObj;
|
||||||
|
void (Obj::*mMethod)(Arg1, Arg2, Arg3);
|
||||||
|
Arg1 mArg1;
|
||||||
|
Arg2 mArg2;
|
||||||
|
Arg3 mArg3;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Socket Interface
|
// Socket Interface
|
||||||
//
|
//
|
||||||
|
@ -88,6 +127,11 @@ typedef
|
||||||
BluetoothInterfaceRunnable1<BluetoothSocketResultHandler, void, int>
|
BluetoothInterfaceRunnable1<BluetoothSocketResultHandler, void, int>
|
||||||
BluetoothSocketIntResultRunnable;
|
BluetoothSocketIntResultRunnable;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
BluetoothInterfaceRunnable3<BluetoothSocketResultHandler,
|
||||||
|
void, int, const nsAString_internal&, int>
|
||||||
|
BluetoothSocketIntStringIntResultRunnable;
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
BluetoothInterfaceRunnable1<BluetoothSocketResultHandler, void, bt_status_t>
|
BluetoothInterfaceRunnable1<BluetoothSocketResultHandler, void, bt_status_t>
|
||||||
BluetoothSocketErrorRunnable;
|
BluetoothSocketErrorRunnable;
|
||||||
|
@ -114,6 +158,31 @@ DispatchBluetoothSocketResult(BluetoothSocketResultHandler* aRes,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsresult
|
||||||
|
DispatchBluetoothSocketResult(
|
||||||
|
BluetoothSocketResultHandler* aRes,
|
||||||
|
void (BluetoothSocketResultHandler::*aMethod)(int, const nsAString&, int),
|
||||||
|
int aArg1, const nsAString& aArg2, int aArg3, bt_status_t aStatus)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aRes);
|
||||||
|
|
||||||
|
nsRunnable* runnable;
|
||||||
|
|
||||||
|
if (aStatus == BT_STATUS_SUCCESS) {
|
||||||
|
runnable = new BluetoothSocketIntStringIntResultRunnable(aRes, aMethod,
|
||||||
|
aArg1, aArg2,
|
||||||
|
aArg3);
|
||||||
|
} else {
|
||||||
|
runnable = new BluetoothSocketErrorRunnable(aRes,
|
||||||
|
&BluetoothSocketResultHandler::OnError, aStatus);
|
||||||
|
}
|
||||||
|
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothSocketInterface::Listen(btsock_type_t aType,
|
BluetoothSocketInterface::Listen(btsock_type_t aType,
|
||||||
const char* aServiceName,
|
const char* aServiceName,
|
||||||
|
@ -131,6 +200,293 @@ BluetoothSocketInterface::Listen(btsock_type_t aType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CMSGHDR_CONTAINS_FD(_cmsghdr) \
|
||||||
|
( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \
|
||||||
|
((_cmsghdr)->cmsg_type == SCM_RIGHTS) )
|
||||||
|
|
||||||
|
/* |SocketMessageWatcher| receives Bluedroid's socket setup
|
||||||
|
* messages on the I/O thread. You need to inherit from this
|
||||||
|
* class to make use of it.
|
||||||
|
*
|
||||||
|
* Bluedroid sends two socket info messages (20 bytes) at
|
||||||
|
* the beginning of a connection to both peers.
|
||||||
|
*
|
||||||
|
* - 1st message: [channel:4]
|
||||||
|
* - 2nd message: [size:2][bd address:6][channel:4][connection status:4]
|
||||||
|
*
|
||||||
|
* On the server side, the second message will contain a
|
||||||
|
* socket file descriptor for the connection. The client
|
||||||
|
* uses the original file descriptor.
|
||||||
|
*/
|
||||||
|
class SocketMessageWatcher : public MessageLoopForIO::Watcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const unsigned char MSG1_SIZE = 4;
|
||||||
|
static const unsigned char MSG2_SIZE = 16;
|
||||||
|
|
||||||
|
static const unsigned char OFF_CHANNEL1 = 0;
|
||||||
|
static const unsigned char OFF_SIZE = 4;
|
||||||
|
static const unsigned char OFF_BDADDRESS = 6;
|
||||||
|
static const unsigned char OFF_CHANNEL2 = 12;
|
||||||
|
static const unsigned char OFF_STATUS = 16;
|
||||||
|
|
||||||
|
SocketMessageWatcher(int aFd)
|
||||||
|
: mFd(aFd)
|
||||||
|
, mClientFd(-1)
|
||||||
|
, mLen(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual ~SocketMessageWatcher()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void Proceed(bt_status_t aStatus) = 0;
|
||||||
|
|
||||||
|
void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
bt_status_t status;
|
||||||
|
|
||||||
|
switch (mLen) {
|
||||||
|
case 0:
|
||||||
|
status = RecvMsg1();
|
||||||
|
break;
|
||||||
|
case MSG1_SIZE:
|
||||||
|
status = RecvMsg2();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* message-size error */
|
||||||
|
status = BT_STATUS_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsComplete() || status != BT_STATUS_SUCCESS) {
|
||||||
|
mWatcher.StopWatchingFileDescriptor();
|
||||||
|
Proceed(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void Watch()
|
||||||
|
{
|
||||||
|
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||||
|
mFd,
|
||||||
|
true,
|
||||||
|
MessageLoopForIO::WATCH_READ,
|
||||||
|
&mWatcher,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsComplete() const
|
||||||
|
{
|
||||||
|
return mLen == (MSG1_SIZE + MSG2_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetFd() const
|
||||||
|
{
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GetChannel1() const
|
||||||
|
{
|
||||||
|
return ReadInt32(OFF_CHANNEL1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GetSize() const
|
||||||
|
{
|
||||||
|
return ReadInt16(OFF_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsString GetBdAddress() const
|
||||||
|
{
|
||||||
|
nsString bdAddress;
|
||||||
|
ReadBdAddress(OFF_BDADDRESS, bdAddress);
|
||||||
|
return bdAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GetChannel2() const
|
||||||
|
{
|
||||||
|
return ReadInt32(OFF_CHANNEL2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t GetConnectionStatus() const
|
||||||
|
{
|
||||||
|
return ReadInt32(OFF_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetClientFd() const
|
||||||
|
{
|
||||||
|
return mClientFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bt_status_t RecvMsg1()
|
||||||
|
{
|
||||||
|
struct iovec iv;
|
||||||
|
memset(&iv, 0, sizeof(iv));
|
||||||
|
iv.iov_base = mBuf;
|
||||||
|
iv.iov_len = MSG1_SIZE;
|
||||||
|
|
||||||
|
struct msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = &iv;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
|
||||||
|
if (res < 0) {
|
||||||
|
return BT_STATUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLen += res;
|
||||||
|
|
||||||
|
return BT_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_status_t RecvMsg2()
|
||||||
|
{
|
||||||
|
struct iovec iv;
|
||||||
|
memset(&iv, 0, sizeof(iv));
|
||||||
|
iv.iov_base = mBuf + MSG1_SIZE;
|
||||||
|
iv.iov_len = MSG2_SIZE;
|
||||||
|
|
||||||
|
struct msghdr msg;
|
||||||
|
struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = &iv;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
msg.msg_control = cmsgbuf;
|
||||||
|
msg.msg_controllen = sizeof(cmsgbuf);
|
||||||
|
|
||||||
|
ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
|
||||||
|
if (res < 0) {
|
||||||
|
return BT_STATUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLen += res;
|
||||||
|
|
||||||
|
if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
|
||||||
|
return BT_STATUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmsghdr *cmsgptr = CMSG_FIRSTHDR(&msg);
|
||||||
|
|
||||||
|
// Extract client fd from message header
|
||||||
|
for (; cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
|
||||||
|
if (CMSGHDR_CONTAINS_FD(cmsgptr)) {
|
||||||
|
// if multiple file descriptors have been sent, we close
|
||||||
|
// all but the final one.
|
||||||
|
if (mClientFd != -1) {
|
||||||
|
TEMP_FAILURE_RETRY(close(mClientFd));
|
||||||
|
}
|
||||||
|
// retrieve sent client fd
|
||||||
|
mClientFd = *(static_cast<int*>(CMSG_DATA(cmsgptr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t ReadInt16(unsigned long aOffset) const
|
||||||
|
{
|
||||||
|
/* little-endian buffer */
|
||||||
|
return (static_cast<int16_t>(mBuf[aOffset + 1]) << 8) |
|
||||||
|
static_cast<int16_t>(mBuf[aOffset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ReadInt32(unsigned long aOffset) const
|
||||||
|
{
|
||||||
|
/* little-endian buffer */
|
||||||
|
return (static_cast<int32_t>(mBuf[aOffset + 3]) << 24) |
|
||||||
|
(static_cast<int32_t>(mBuf[aOffset + 2]) << 16) |
|
||||||
|
(static_cast<int32_t>(mBuf[aOffset + 1]) << 8) |
|
||||||
|
static_cast<int32_t>(mBuf[aOffset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadBdAddress(unsigned long aOffset, nsAString& aBdAddress) const
|
||||||
|
{
|
||||||
|
char str[18];
|
||||||
|
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
mBuf[aOffset + 0], mBuf[aOffset + 1], mBuf[aOffset + 2],
|
||||||
|
mBuf[aOffset + 3], mBuf[aOffset + 4], mBuf[aOffset + 5]);
|
||||||
|
aBdAddress.AssignLiteral(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageLoopForIO::FileDescriptorWatcher mWatcher;
|
||||||
|
int mFd;
|
||||||
|
int mClientFd;
|
||||||
|
unsigned char mLen;
|
||||||
|
uint8_t mBuf[MSG1_SIZE + MSG2_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* |SocketMessageWatcherTask| starts a SocketMessageWatcher
|
||||||
|
* on the I/O task
|
||||||
|
*/
|
||||||
|
class SocketMessageWatcherTask MOZ_FINAL : public Task
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SocketMessageWatcherTask(SocketMessageWatcher* aWatcher)
|
||||||
|
: mWatcher(aWatcher)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mWatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
mWatcher->Watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SocketMessageWatcher* mWatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* |DeleteTask| deletes a class instance on the I/O thread
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class DeleteTask MOZ_FINAL : public Task
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeleteTask(T* aPtr)
|
||||||
|
: mPtr(aPtr)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void Run() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
mPtr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsAutoPtr<T> mPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* |ConnectWatcher| specializes SocketMessageWatcher for
|
||||||
|
* connect operations by reading the socket messages from
|
||||||
|
* Bluedroid and forwarding the connected socket to the
|
||||||
|
* resource handler.
|
||||||
|
*/
|
||||||
|
class ConnectWatcher MOZ_FINAL : public SocketMessageWatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes)
|
||||||
|
: SocketMessageWatcher(aFd)
|
||||||
|
, mRes(aRes)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void Proceed(bt_status_t aStatus) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
if (mRes) {
|
||||||
|
DispatchBluetoothSocketResult(mRes,
|
||||||
|
&BluetoothSocketResultHandler::Connect,
|
||||||
|
GetFd(), GetBdAddress(),
|
||||||
|
GetConnectionStatus(), aStatus);
|
||||||
|
}
|
||||||
|
MessageLoopForIO::current()->PostTask(
|
||||||
|
FROM_HERE, new DeleteTask<ConnectWatcher>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<BluetoothSocketResultHandler> mRes;
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothSocketInterface::Connect(const bt_bdaddr_t* aBdAddr,
|
BluetoothSocketInterface::Connect(const bt_bdaddr_t* aBdAddr,
|
||||||
btsock_type_t aType, const uint8_t* aUuid,
|
btsock_type_t aType, const uint8_t* aUuid,
|
||||||
|
@ -141,10 +497,14 @@ BluetoothSocketInterface::Connect(const bt_bdaddr_t* aBdAddr,
|
||||||
|
|
||||||
bt_status_t status = mInterface->connect(aBdAddr, aType, aUuid, aChannel,
|
bt_status_t status = mInterface->connect(aBdAddr, aType, aUuid, aChannel,
|
||||||
&fd, aFlags);
|
&fd, aFlags);
|
||||||
if (aRes) {
|
if (status == BT_STATUS_SUCCESS) {
|
||||||
DispatchBluetoothSocketResult(aRes,
|
/* receive Bluedroid's socket-setup messages */
|
||||||
&BluetoothSocketResultHandler::Connect,
|
Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes));
|
||||||
fd, status);
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
|
||||||
|
} else if (aRes) {
|
||||||
|
DispatchBluetoothSocketResult(aRes,
|
||||||
|
&BluetoothSocketResultHandler::Connect,
|
||||||
|
-1, EmptyString(), 0, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Listen(int aSockFd) { }
|
virtual void Listen(int aSockFd) { }
|
||||||
virtual void Connect(int aSockFd) { }
|
virtual void Connect(int aSockFd, const nsAString& aBdAddress,
|
||||||
|
int aConnectionState) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothSocketInterface
|
class BluetoothSocketInterface
|
||||||
|
|
|
@ -263,6 +263,70 @@ private:
|
||||||
T* mInstance;
|
T* mInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DroidSocketImplRunnable : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DroidSocketImpl* GetImpl() const
|
||||||
|
{
|
||||||
|
return mImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DroidSocketImplRunnable(DroidSocketImpl* aImpl)
|
||||||
|
: mImpl(aImpl)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~DroidSocketImplRunnable()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DroidSocketImpl* mImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OnSocketEventRunnable : public DroidSocketImplRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum SocketEvent {
|
||||||
|
CONNECT_SUCCESS,
|
||||||
|
CONNECT_ERROR,
|
||||||
|
DISCONNECT
|
||||||
|
};
|
||||||
|
|
||||||
|
OnSocketEventRunnable(DroidSocketImpl* aImpl, SocketEvent e)
|
||||||
|
: DroidSocketImplRunnable(aImpl)
|
||||||
|
, mEvent(e)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
DroidSocketImpl* impl = GetImpl();
|
||||||
|
|
||||||
|
if (impl->IsShutdownOnMainThread()) {
|
||||||
|
NS_WARNING("CloseSocket has already been called!");
|
||||||
|
// Since we've already explicitly closed and the close happened before
|
||||||
|
// this, this isn't really an error. Since we've warned, return OK.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
if (mEvent == CONNECT_SUCCESS) {
|
||||||
|
impl->mConsumer->NotifySuccess();
|
||||||
|
} else if (mEvent == CONNECT_ERROR) {
|
||||||
|
impl->mConsumer->NotifyError();
|
||||||
|
} else if (mEvent == DISCONNECT) {
|
||||||
|
impl->mConsumer->NotifyDisconnect();
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SocketEvent mEvent;
|
||||||
|
};
|
||||||
|
|
||||||
class RequestClosingSocketTask : public nsRunnable
|
class RequestClosingSocketTask : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -467,7 +531,7 @@ DroidSocketImpl::Connect(int aFd)
|
||||||
SetFd(aFd);
|
SetFd(aFd);
|
||||||
mConnectionStatus = SOCKET_IS_CONNECTING;
|
mConnectionStatus = SOCKET_IS_CONNECTING;
|
||||||
|
|
||||||
AddWatchers(READ_WATCHER, true);
|
AddWatchers(WRITE_WATCHER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -550,9 +614,6 @@ DroidSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
|
||||||
OnSocketCanReceiveWithoutBlocking(aFd);
|
OnSocketCanReceiveWithoutBlocking(aFd);
|
||||||
} else if (mConnectionStatus == SOCKET_IS_LISTENING) {
|
} else if (mConnectionStatus == SOCKET_IS_LISTENING) {
|
||||||
OnSocketCanAcceptWithoutBlocking(aFd);
|
OnSocketCanAcceptWithoutBlocking(aFd);
|
||||||
} else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
|
|
||||||
/* TODO: remove this branch when connect is handled by BluetoothInterface */
|
|
||||||
OnSocketCanConnectWithoutBlocking(aFd);
|
|
||||||
} else {
|
} else {
|
||||||
NS_NOTREACHED("invalid connection state for reading");
|
NS_NOTREACHED("invalid connection state for reading");
|
||||||
}
|
}
|
||||||
|
@ -720,51 +781,20 @@ DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||||
|
|
||||||
// Read all of the incoming data.
|
/* We follow Posix behaviour here: Connect operations are
|
||||||
while (true) {
|
* complete once we can write to the connecting socket.
|
||||||
nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
|
*/
|
||||||
|
|
||||||
ssize_t ret;
|
mConnectionStatus = SOCKET_IS_CONNECTED;
|
||||||
if (!mReadMsgForClientFd) {
|
|
||||||
ret = read(aFd, incoming->mData, incoming->mSize);
|
|
||||||
} else {
|
|
||||||
ret = ReadMsg(aFd, incoming->mData, incoming->mSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret <= 0) {
|
nsRefPtr<OnSocketEventRunnable> r =
|
||||||
if (ret == -1) {
|
new OnSocketEventRunnable(this, OnSocketEventRunnable::CONNECT_SUCCESS);
|
||||||
if (errno == EINTR) {
|
NS_DispatchToMainThread(r);
|
||||||
continue; // retry system call when interrupted
|
|
||||||
}
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
||||||
return; // no data available: return and re-poll
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_WARNING("Cannot read from network");
|
AddWatchers(READ_WATCHER, true);
|
||||||
// else fall through to error handling on other errno's
|
if (!mOutgoingQ.IsEmpty()) {
|
||||||
}
|
AddWatchers(WRITE_WATCHER, false);
|
||||||
|
|
||||||
// We're done with our descriptors. Ensure that spurious events don't
|
|
||||||
// cause us to end up back here.
|
|
||||||
RemoveWatchers(READ_WATCHER | WRITE_WATCHER);
|
|
||||||
nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
|
|
||||||
NS_DispatchToMainThread(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
incoming->mSize = ret;
|
|
||||||
nsRefPtr<SocketReceiveTask> t =
|
|
||||||
new SocketReceiveTask(this, incoming.forget());
|
|
||||||
NS_DispatchToMainThread(t);
|
|
||||||
|
|
||||||
// If ret is less than MAX_READ_SIZE, there's no
|
|
||||||
// more data in the socket for us to read now.
|
|
||||||
if (ret < ssize_t(MAX_READ_SIZE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CRASH("We returned early");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
|
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
|
||||||
|
@ -811,9 +841,14 @@ public:
|
||||||
MOZ_ASSERT(mImpl);
|
MOZ_ASSERT(mImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connect(int aFd) MOZ_OVERRIDE
|
void Connect(int aFd, const nsAString& aBdAddress,
|
||||||
|
int aConnectionStatus) MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (!mImpl->IsShutdownOnMainThread()) {
|
||||||
|
mImpl->mConsumer->SetAddress(aBdAddress);
|
||||||
|
}
|
||||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||||
new SocketConnectTask(mImpl, aFd));
|
new SocketConnectTask(mImpl, aFd));
|
||||||
}
|
}
|
||||||
|
@ -964,7 +999,8 @@ BluetoothSocket::ReceiveSocketInfo(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||||
void
|
void
|
||||||
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
|
||||||
{
|
{
|
||||||
if (ReceiveSocketInfo(aMessage)) {
|
/* clients handle socket setup in BluetoothInterface::Connect */
|
||||||
|
if (mIsServer && ReceiveSocketInfo(aMessage)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,6 @@ public:
|
||||||
bool aAuth,
|
bool aAuth,
|
||||||
bool aEncrypt);
|
bool aEncrypt);
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect to remote server as a client.
|
|
||||||
*
|
|
||||||
* The steps are as following:
|
|
||||||
* 1) BluetoothSocket acquires fd from bluedroid, and creates
|
|
||||||
* a DroidSocketImpl to watch read/write of the fd.
|
|
||||||
* 2) DroidSocketImpl receives first 2 messages to get socket info.
|
|
||||||
* 3) Obex client session starts.
|
|
||||||
*/
|
|
||||||
bool Connect(const nsAString& aDeviceAddress, int aChannel);
|
bool Connect(const nsAString& aDeviceAddress, int aChannel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +56,11 @@ public:
|
||||||
aDeviceAddress = mDeviceAddress;
|
aDeviceAddress = mDeviceAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void SetAddress(const nsAString& aDeviceAddress)
|
||||||
|
{
|
||||||
|
mDeviceAddress = aDeviceAddress;
|
||||||
|
}
|
||||||
|
|
||||||
void CloseDroidSocket();
|
void CloseDroidSocket();
|
||||||
bool SendDroidSocketData(mozilla::ipc::UnixSocketRawData* aData);
|
bool SendDroidSocketData(mozilla::ipc::UnixSocketRawData* aData);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче