Commit ef2f0027 authored by xiyuan@chromium.org's avatar xiyuan@chromium.org

win: Implement Bluetooth server.

BUG=333979

Review URL: https://codereview.chromium.org/236203018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266831 0039d316-1c4b-4281-b951-d872f2087c98
parent 3c053313
......@@ -72,6 +72,13 @@ class BluetoothAdapterWin : public BluetoothAdapter,
const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices)
OVERRIDE;
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner() const {
return ui_task_runner_;
}
const scoped_refptr<BluetoothSocketThreadWin>& socket_thread() const {
return socket_thread_;
}
protected:
// BluetoothAdapter:
virtual void RemovePairingDelegateInternal(
......
......@@ -58,9 +58,9 @@ void BluetoothProfile::Register(const BluetoothUUID& uuid,
profile = CreateBluetoothProfileMac(uuid, options);
callback.Run(profile);
#elif defined(OS_WIN)
BluetoothProfile* profile = NULL;
profile = new BluetoothProfileWin(uuid, options.name);
callback.Run(profile);
BluetoothProfileWin* profile = NULL;
profile = new BluetoothProfileWin();
profile->Init(uuid, options, callback);
#else
callback.Run(NULL);
#endif
......
......@@ -5,9 +5,12 @@
#include "device/bluetooth/bluetooth_profile_win.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_adapter_win.h"
#include "device/bluetooth/bluetooth_device_win.h"
#include "device/bluetooth/bluetooth_service_record.h"
#include "device/bluetooth/bluetooth_socket_thread_win.h"
......@@ -62,19 +65,36 @@ void OnConnectErrorUI(scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
error_callback.Run(error);
}
std::string IPEndPointToBluetoothAddress(const net::IPEndPoint& end_point) {
if (end_point.address().size() != net::kBluetoothAddressSize)
return std::string();
// The address is copied from BTH_ADDR field of SOCKADDR_BTH, which is a
// 64-bit ULONGLONG that stores Bluetooth address in little-endian. Print in
// reverse order to preserve the correct ordering.
return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
end_point.address()[5],
end_point.address()[4],
end_point.address()[3],
end_point.address()[2],
end_point.address()[1],
end_point.address()[0]);
}
} // namespace
namespace device {
BluetoothProfileWin::BluetoothProfileWin(const BluetoothUUID& uuid,
const std::string& name)
: BluetoothProfile(), uuid_(uuid), name_(name) {
BluetoothProfileWin::BluetoothProfileWin()
: BluetoothProfile(), rfcomm_channel_(0), weak_ptr_factory_(this) {
}
BluetoothProfileWin::~BluetoothProfileWin() {
}
void BluetoothProfileWin::Unregister() {
if (profile_socket_)
profile_socket_->Close();
delete this;
}
......@@ -83,6 +103,19 @@ void BluetoothProfileWin::SetConnectionCallback(
connection_callback_ = callback;
}
void BluetoothProfileWin::Init(const BluetoothUUID& uuid,
const BluetoothProfile::Options& options,
const ProfileCallback& callback) {
uuid_ = uuid;
name_ = options.name;
rfcomm_channel_ = options.channel;
BluetoothAdapterFactory::GetAdapter(
base::Bind(&BluetoothProfileWin::OnGetAdapter,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void BluetoothProfileWin::Connect(
const BluetoothDeviceWin* device,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
......@@ -105,9 +138,10 @@ void BluetoothProfileWin::Connect(
scoped_refptr<BluetoothSocketWin> socket(
BluetoothSocketWin::CreateBluetoothSocket(
*record, ui_task_runner, socket_thread, net_log, source));
ui_task_runner, socket_thread, net_log, source));
socket->Connect(base::Bind(&OnConnectSuccessUI,
socket->Connect(*record,
base::Bind(&OnConnectSuccessUI,
ui_task_runner,
success_callback,
connection_callback_,
......@@ -116,4 +150,73 @@ void BluetoothProfileWin::Connect(
error_callback);
}
void BluetoothProfileWin::OnGetAdapter(
const ProfileCallback& callback,
scoped_refptr<BluetoothAdapter> in_adapter) {
DCHECK(!adapter_);
DCHECK(!profile_socket_);
adapter_ = in_adapter;
profile_socket_ = BluetoothSocketWin::CreateBluetoothSocket(
adapter()->ui_task_runner(),
adapter()->socket_thread(),
NULL,
net::NetLog::Source());
profile_socket_->StartService(
uuid_,
name_,
rfcomm_channel_,
base::Bind(&BluetoothProfileWin::OnRegisterProfileSuccess,
weak_ptr_factory_.GetWeakPtr(),
callback),
base::Bind(&BluetoothProfileWin::OnRegisterProfileError,
weak_ptr_factory_.GetWeakPtr(),
callback),
base::Bind(&BluetoothProfileWin::OnNewConnection,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothProfileWin::OnRegisterProfileSuccess(
const ProfileCallback& callback) {
callback.Run(this);
}
void BluetoothProfileWin::OnRegisterProfileError(
const ProfileCallback& callback,
const std::string& error_message) {
callback.Run(NULL);
delete this;
}
void BluetoothProfileWin::OnNewConnection(
scoped_refptr<BluetoothSocketWin> connected,
const net::IPEndPoint& peer_address) {
DCHECK(adapter()->ui_task_runner()->RunsTasksOnCurrentThread());
if (connection_callback_.is_null())
return;
std::string device_address = IPEndPointToBluetoothAddress(peer_address);
if (device_address.empty()) {
LOG(WARNING) << "Failed to accept connection for profile "
<< "uuid=" << uuid_.value()
<< ", unexpected peer device address.";
return;
}
BluetoothDevice* device = adapter_->GetDevice(device_address);
if (!device) {
LOG(WARNING) << "Failed to accept connection for profile"
<< ",uuid=" << uuid_.value()
<< ", unknown device=" << device_address;
return;
}
connection_callback_.Run(device, connected);
}
BluetoothAdapterWin* BluetoothProfileWin::adapter() const {
DCHECK(adapter_);
return static_cast<BluetoothAdapterWin*>(adapter_.get());
}
} // namespace device
......@@ -7,23 +7,39 @@
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "device/bluetooth/bluetooth_profile.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "net/base/net_log.h"
#include "net/socket/tcp_socket.h"
namespace net {
class IPEndPoint;
}
namespace device {
class BluetoothAdapter;
class BluetoothAdapterWin;
class BluetoothDeviceWin;
class BluetoothSocketThreadWin;
class BluetoothSocketWin;
class BluetoothProfileWin : public BluetoothProfile {
public:
typedef base::Callback<void(const std::string&)> ErrorCallback;
// BluetoothProfile override.
virtual void Unregister() OVERRIDE;
virtual void SetConnectionCallback(
const ConnectionCallback& callback) OVERRIDE;
typedef base::Callback<void(const std::string&)> ErrorCallback;
// Called by BluetoothProfile::Register to initialize the profile object
// asynchronously.
void Init(const BluetoothUUID& uuid,
const device::BluetoothProfile::Options& options,
const ProfileCallback& callback);
void Connect(const BluetoothDeviceWin* device,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
......@@ -36,13 +52,33 @@ class BluetoothProfileWin : public BluetoothProfile {
private:
friend BluetoothProfile;
BluetoothProfileWin(const BluetoothUUID& uuid, const std::string& name);
BluetoothProfileWin();
virtual ~BluetoothProfileWin();
const BluetoothUUID uuid_;
const std::string name_;
// Internal method run to get the adapter object during initialization.
void OnGetAdapter(const ProfileCallback& callback,
scoped_refptr<BluetoothAdapter> adapter);
// Callbacks for |profile_socket_|'s StartService call.
void OnRegisterProfileSuccess(const ProfileCallback& callback);
void OnRegisterProfileError(const ProfileCallback& callback,
const std::string& error_message);
// Callback when |profile_socket_| accepts a connection.
void OnNewConnection(scoped_refptr<BluetoothSocketWin> connected,
const net::IPEndPoint& peer_address);
BluetoothAdapterWin* adapter() const;
BluetoothUUID uuid_;
std::string name_;
int rfcomm_channel_;
ConnectionCallback connection_callback_;
scoped_refptr<BluetoothAdapter> adapter_;
scoped_refptr<BluetoothSocketWin> profile_socket_;
base::WeakPtrFactory<BluetoothProfileWin> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BluetoothProfileWin);
};
......
This diff is collapsed.
......@@ -15,6 +15,7 @@
#include "base/threading/thread_checker.h"
#include "device/bluetooth/bluetooth_service_record_win.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_log.h"
#include "net/socket/tcp_socket.h"
......@@ -34,17 +35,32 @@ class BluetoothSocketThreadWin;
// separated thread.
class BluetoothSocketWin : public BluetoothSocket {
public:
typedef base::Callback<void(scoped_refptr<BluetoothSocketWin>,
const net::IPEndPoint&)> OnNewConnectionCallback;
static scoped_refptr<BluetoothSocketWin> CreateBluetoothSocket(
const BluetoothServiceRecord& service_record,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
scoped_refptr<BluetoothSocketThreadWin> socket_thread,
net::NetLog* net_log,
const net::NetLog::Source& source);
// Connect to the peer device and calls |success_callback| when the
// Starts a service with the given uuid, name and rfcomm_channel.
// |success_callback| is invoked when the underlying socket is created
// and the service is published successfully. Otherwise, |error_callback| is
// called with an error message. |new_connection_callback| is invoked when
// an incoming connection is accepted by the underlying socket.
void StartService(
const BluetoothUUID& uuid,
const std::string& name,
int rfcomm_channel,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback,
const OnNewConnectionCallback& new_connection_callback);
// connection has been established successfully. If an error occurs, calls
// |error_callback| with a system error message.
void Connect(const base::Closure& success_callback,
void Connect(const BluetoothServiceRecord& service_record,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
// Overriden from BluetoothSocket:
......@@ -65,6 +81,8 @@ class BluetoothSocketWin : public BluetoothSocket {
virtual ~BluetoothSocketWin();
private:
struct ServiceRegData;
struct WriteRequest {
scoped_refptr<net::IOBuffer> buffer;
int buffer_size;
......@@ -111,6 +129,17 @@ class BluetoothSocketWin : public BluetoothSocket {
const ReceiveErrorCompletionCallback& error_callback,
int send_result);
void DoStartService(const BluetoothUUID& uuid,
const std::string& name,
int rfcomm_channel,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback,
const OnNewConnectionCallback& new_connection_callback);
void DoAccept();
void OnAcceptOnSocketThread(int accept_result);
void OnAcceptOnUI(scoped_ptr<net::TCPSocket> accept_socket,
const net::IPEndPoint& peer_address);
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
scoped_refptr<BluetoothSocketThreadWin> socket_thread_;
net::NetLog* net_log_;
......@@ -125,6 +154,11 @@ class BluetoothSocketWin : public BluetoothSocket {
std::queue<linked_ptr<WriteRequest> > write_queue_;
scoped_refptr<net::IOBufferWithSize> read_buffer_;
scoped_ptr<ServiceRegData> service_reg_data_;
scoped_ptr<net::TCPSocket> accept_socket_;
net::IPEndPoint accept_address_;
OnNewConnectionCallback on_new_connection_callback_;
DISALLOW_COPY_AND_ASSIGN(BluetoothSocketWin);
};
......
......@@ -16,6 +16,7 @@
#include <windows.h>
#include <iphlpapi.h>
#include <winsock2.h>
#include <ws2bth.h>
#pragma comment(lib, "iphlpapi.lib")
#elif defined(OS_POSIX)
#include <fcntl.h>
......@@ -524,13 +525,27 @@ bool GetIPAddressFromSockAddr(const struct sockaddr* sock_addr,
return false;
const struct sockaddr_in6* addr =
reinterpret_cast<const struct sockaddr_in6*>(sock_addr);
*address = reinterpret_cast<const unsigned char*>(&addr->sin6_addr);
*address = reinterpret_cast<const uint8*>(&addr->sin6_addr);
*address_len = kIPv6AddressSize;
if (port)
*port = base::NetToHost16(addr->sin6_port);
return true;
}
#if defined(OS_WIN)
if (sock_addr->sa_family == AF_BTH) {
if (sock_addr_len < static_cast<socklen_t>(sizeof(SOCKADDR_BTH)))
return false;
const SOCKADDR_BTH* addr =
reinterpret_cast<const SOCKADDR_BTH*>(sock_addr);
*address = reinterpret_cast<const uint8*>(&addr->btAddr);
*address_len = kBluetoothAddressSize;
if (port)
*port = addr->port;
return true;
}
#endif
return false; // Unrecognized |sa_family|.
}
......
......@@ -52,6 +52,10 @@ typedef std::vector<IPAddressNumber> IPAddressList;
static const size_t kIPv4AddressSize = 4;
static const size_t kIPv6AddressSize = 16;
#if defined(OS_WIN)
// Bluetooth address size. Windows Bluetooth is supported via winsock.
static const size_t kBluetoothAddressSize = 6;
#endif
// Nothing is ommitted.
NET_EXPORT extern const FormatUrlType kFormatUrlOmitNothing;
......
......@@ -64,6 +64,28 @@ class TCPSocketTest : public PlatformTest {
*address = IPEndPoint(ip_number, port);
}
void TestAcceptAsync() {
TestCompletionCallback accept_callback;
scoped_ptr<TCPSocket> accepted_socket;
IPEndPoint accepted_address;
ASSERT_EQ(ERR_IO_PENDING,
socket_.Accept(&accepted_socket, &accepted_address,
accept_callback.callback()));
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(),
NULL, NetLog::Source());
connecting_socket.Connect(connect_callback.callback());
EXPECT_EQ(OK, connect_callback.WaitForResult());
EXPECT_EQ(OK, accept_callback.WaitForResult());
EXPECT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
}
AddressList local_address_list() const {
return AddressList(local_address_);
}
......@@ -103,27 +125,28 @@ TEST_F(TCPSocketTest, Accept) {
// Test Accept() callback.
TEST_F(TCPSocketTest, AcceptAsync) {
ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
TestAcceptAsync();
}
TestCompletionCallback accept_callback;
scoped_ptr<TCPSocket> accepted_socket;
IPEndPoint accepted_address;
ASSERT_EQ(ERR_IO_PENDING,
socket_.Accept(&accepted_socket, &accepted_address,
accept_callback.callback()));
#if defined(OS_WIN)
// Test Accept() for AdoptListenSocket.
TEST_F(TCPSocketTest, AcceptForAdoptedListenSocket) {
// Create a socket to be used with AdoptListenSocket.
SOCKET existing_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ASSERT_EQ(OK, socket_.AdoptListenSocket(existing_socket));
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(),
NULL, NetLog::Source());
connecting_socket.Connect(connect_callback.callback());
IPEndPoint address;
ParseAddress("127.0.0.1", 0, &address);
SockaddrStorage storage;
ASSERT_TRUE(address.ToSockAddr(storage.addr, &storage.addr_len));
ASSERT_EQ(0, bind(existing_socket, storage.addr, storage.addr_len));
EXPECT_EQ(OK, connect_callback.WaitForResult());
EXPECT_EQ(OK, accept_callback.WaitForResult());
ASSERT_EQ(OK, socket_.Listen(kListenBacklog));
ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
EXPECT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
TestAcceptAsync();
}
#endif
// Accept two connections simultaneously.
TEST_F(TCPSocketTest, Accept2Connections) {
......
......@@ -322,6 +322,24 @@ int TCPSocketWin::AdoptConnectedSocket(SOCKET socket,
return OK;
}
int TCPSocketWin::AdoptListenSocket(SOCKET socket) {
DCHECK(CalledOnValidThread());
DCHECK_EQ(socket_, INVALID_SOCKET);
socket_ = socket;
if (SetNonBlocking(socket_)) {
int result = MapSystemError(WSAGetLastError());
Close();
return result;
}
// |core_| is not needed for sockets that are used to accept connections.
// The operation here is more like Open but with an existing socket.
return OK;
}
int TCPSocketWin::Bind(const IPEndPoint& address) {
DCHECK(CalledOnValidThread());
DCHECK_NE(socket_, INVALID_SOCKET);
......
......@@ -31,8 +31,13 @@ class NET_EXPORT TCPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe),
virtual ~TCPSocketWin();
int Open(AddressFamily family);
// Takes ownership of |socket|.
// Both AdoptConnectedSocket and AdoptListenSocket take ownership of an
// existing socket. AdoptConnectedSocket takes an already connected
// socket. AdoptListenSocket takes a socket that is intended to accept
// connection. In some sense, AdoptListenSocket is more similar to Open.
int AdoptConnectedSocket(SOCKET socket, const IPEndPoint& peer_address);
int AdoptListenSocket(SOCKET socket);
int Bind(const IPEndPoint& address);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment