summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 10:24:35 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 10:24:35 +0000
commitef2f002744fa3b40f0da96b959b5defa0dd2f565 (patch)
tree24d0e4f30c84811887d0877156a3cca98bc33854
parent3c05331313cf4d8569b656ced2e09ed2ed3cdbb4 (diff)
downloadchromium_src-ef2f002744fa3b40f0da96b959b5defa0dd2f565.zip
chromium_src-ef2f002744fa3b40f0da96b959b5defa0dd2f565.tar.gz
chromium_src-ef2f002744fa3b40f0da96b959b5defa0dd2f565.tar.bz2
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
-rw-r--r--device/bluetooth/bluetooth_adapter_win.h7
-rw-r--r--device/bluetooth/bluetooth_profile.cc6
-rw-r--r--device/bluetooth/bluetooth_profile_win.cc113
-rw-r--r--device/bluetooth/bluetooth_profile_win.h44
-rw-r--r--device/bluetooth/bluetooth_socket_win.cc227
-rw-r--r--device/bluetooth/bluetooth_socket_win.h40
-rw-r--r--net/base/net_util.cc17
-rw-r--r--net/base/net_util.h4
-rw-r--r--net/socket/tcp_socket_unittest.cc55
-rw-r--r--net/socket/tcp_socket_win.cc18
-rw-r--r--net/socket/tcp_socket_win.h7
11 files changed, 493 insertions, 45 deletions
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h
index 388f5e7..7aecb493 100644
--- a/device/bluetooth/bluetooth_adapter_win.h
+++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -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(
diff --git a/device/bluetooth/bluetooth_profile.cc b/device/bluetooth/bluetooth_profile.cc
index 1e41b26..5cf421c 100644
--- a/device/bluetooth/bluetooth_profile.cc
+++ b/device/bluetooth/bluetooth_profile.cc
@@ -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
diff --git a/device/bluetooth/bluetooth_profile_win.cc b/device/bluetooth/bluetooth_profile_win.cc
index 79848ca..8495224 100644
--- a/device/bluetooth/bluetooth_profile_win.cc
+++ b/device/bluetooth/bluetooth_profile_win.cc
@@ -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
diff --git a/device/bluetooth/bluetooth_profile_win.h b/device/bluetooth/bluetooth_profile_win.h
index e235bd2..5e0e914 100644
--- a/device/bluetooth/bluetooth_profile_win.h
+++ b/device/bluetooth/bluetooth_profile_win.h
@@ -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);
};
diff --git a/device/bluetooth/bluetooth_socket_win.cc b/device/bluetooth/bluetooth_socket_win.cc
index addcd77..2371d21 100644
--- a/device/bluetooth/bluetooth_socket_win.cc
+++ b/device/bluetooth/bluetooth_socket_win.cc
@@ -4,12 +4,15 @@
#include "device/bluetooth/bluetooth_socket_win.h"
+#include <objbase.h>
+
#include <string>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "device/bluetooth/bluetooth_init_win.h"
#include "device/bluetooth/bluetooth_service_record_win.h"
@@ -24,6 +27,13 @@ namespace {
const char kL2CAPNotSupported[] = "Bluetooth L2CAP protocal is not supported";
const char kSocketAlreadyConnected[] = "Socket is already connected.";
const char kSocketNotConnected[] = "Socket is not connected.";
+const char kInvalidRfcommPort[] = "Invalid RFCCOMM port.";
+const char kFailedToCreateSocket[] = "Failed to create socket.";
+const char kFailedToBindSocket[] = "Failed to bind socket.";
+const char kFailedToListenOnSocket[] = "Failed to listen on socket.";
+const char kFailedToGetSockNameForSocket[] = "Failed to getsockname.";
+const char kBadUuid[] = "Bad uuid.";
+const char kWsaSetServiceError[] = "WSASetService error.";
using device::BluetoothSocketWin;
@@ -36,27 +46,31 @@ static void DeactivateSocket(
namespace device {
+struct BluetoothSocketWin::ServiceRegData {
+ ServiceRegData() {
+ ZeroMemory(&address, sizeof(address));
+ ZeroMemory(&address_info, sizeof(address_info));
+ ZeroMemory(&uuid, sizeof(uuid));
+ ZeroMemory(&service, sizeof(service));
+ }
+
+ SOCKADDR_BTH address;
+ CSADDR_INFO address_info;
+ GUID uuid;
+ base::string16 name;
+ WSAQUERYSET service;
+};
+
// static
scoped_refptr<BluetoothSocketWin> 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) {
DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
- const BluetoothServiceRecordWin* service_record_win =
- static_cast<const BluetoothServiceRecordWin*>(&service_record);
- scoped_refptr<BluetoothSocketWin> result(
+ return make_scoped_refptr(
new BluetoothSocketWin(ui_task_runner, socket_thread, net_log, source));
- result->device_address_ = service_record_win->address();
- if (service_record.SupportsRfcomm()) {
- result->supports_rfcomm_ = true;
- result->rfcomm_channel_ = service_record_win->rfcomm_channel();
- result->bth_addr_ = service_record_win->bth_addr();
- }
-
- return result;
}
BluetoothSocketWin::BluetoothSocketWin(
@@ -80,6 +94,27 @@ BluetoothSocketWin::~BluetoothSocketWin() {
base::Bind(&DeactivateSocket, socket_thread_));
}
+void BluetoothSocketWin::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) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+
+ socket_thread_->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothSocketWin::DoStartService,
+ this,
+ uuid,
+ name,
+ rfcomm_channel,
+ success_callback,
+ error_callback,
+ new_connection_callback));
+}
+
void BluetoothSocketWin::Close() {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
socket_thread_->task_runner()->PostTask(
@@ -87,9 +122,20 @@ void BluetoothSocketWin::Close() {
}
void BluetoothSocketWin::Connect(
+ const BluetoothServiceRecord& service_record,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+
+ const BluetoothServiceRecordWin* service_record_win =
+ static_cast<const BluetoothServiceRecordWin*>(&service_record);
+ device_address_ = service_record_win->address();
+ if (service_record.SupportsRfcomm()) {
+ supports_rfcomm_ = true;
+ rfcomm_channel_ = service_record_win->rfcomm_channel();
+ bth_addr_ = service_record_win->bth_addr();
+ }
+
socket_thread_->task_runner()->PostTask(
FROM_HERE,
base::Bind(
@@ -162,6 +208,14 @@ void BluetoothSocketWin::DoClose() {
read_buffer_ = NULL;
std::queue<linked_ptr<WriteRequest> > empty;
write_queue_.swap(empty);
+
+ if (service_reg_data_) {
+ if (WSASetService(&service_reg_data_->service,RNRSERVICE_DELETE, 0) ==
+ SOCKET_ERROR) {
+ LOG(WARNING) << "Failed to unregister service.";
+ }
+ service_reg_data_.reset();
+ }
}
void BluetoothSocketWin::DoConnect(
@@ -388,4 +442,153 @@ void BluetoothSocketWin::PostSendCompletion(
ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, bytes_written));
}
+void BluetoothSocketWin::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) {
+ DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
+ DCHECK(!tcp_socket_ &&
+ !service_reg_data_ &&
+ on_new_connection_callback_.is_null());
+
+ // The valid range is 0-30. 0 means BT_PORT_ANY and 1-30 are the
+ // valid RFCOMM port numbers of SOCKADDR_BTH.
+ if (rfcomm_channel < 0 || rfcomm_channel > 30) {
+ LOG(WARNING) << "Failed to start service: "
+ << "Invalid RFCCOMM port " << rfcomm_channel
+ << ", uuid=" << uuid.value();
+ PostErrorCompletion(error_callback, kInvalidRfcommPort);
+ return;
+ }
+
+ SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
+ if (socket_fd == INVALID_SOCKET) {
+ LOG(WARNING) << "Failed to start service: create socket, "
+ << "winsock err=" << WSAGetLastError();
+ PostErrorCompletion(error_callback, kFailedToCreateSocket);
+ return;
+ }
+
+ // Note that |socket_fd| belongs to a non-TCP address family (i.e. AF_BTH),
+ // TCPSocket methods that involve address could not be called. So bind()
+ // is called on |socket_fd| directly.
+ scoped_ptr<net::TCPSocket> scoped_socket(
+ new net::TCPSocket(NULL, net::NetLog::Source()));
+ scoped_socket->AdoptListenSocket(socket_fd);
+
+ SOCKADDR_BTH sa;
+ struct sockaddr* sock_addr = reinterpret_cast<struct sockaddr*>(&sa);
+ int sock_addr_len = sizeof(sa);
+ ZeroMemory(&sa, sock_addr_len);
+ sa.addressFamily = AF_BTH;
+ sa.port = rfcomm_channel ? rfcomm_channel : BT_PORT_ANY;
+ if (bind(socket_fd, sock_addr, sock_addr_len) < 0) {
+ LOG(WARNING) << "Failed to start service: create socket, "
+ << "winsock err=" << WSAGetLastError();
+ PostErrorCompletion(error_callback, kFailedToBindSocket);
+ return;
+ }
+
+ const int kListenBacklog = 5;
+ if (scoped_socket->Listen(kListenBacklog) < 0) {
+ LOG(WARNING) << "Failed to start service: Listen"
+ << "winsock err=" << WSAGetLastError();
+ PostErrorCompletion(error_callback, kFailedToListenOnSocket);
+ return;
+ }
+
+ scoped_ptr<ServiceRegData> reg_data(new ServiceRegData);
+ reg_data->name = base::UTF8ToUTF16(name);
+
+ if (getsockname(socket_fd, sock_addr, &sock_addr_len)) {
+ LOG(WARNING) << "Failed to start service: getsockname, "
+ << "winsock err=" << WSAGetLastError();
+ PostErrorCompletion(error_callback, kFailedToGetSockNameForSocket);
+ return;
+ }
+ reg_data->address = sa;
+
+ reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa);
+ reg_data->address_info.LocalAddr.lpSockaddr =
+ reinterpret_cast<struct sockaddr*>(&reg_data->address);
+ reg_data->address_info.iSocketType = SOCK_STREAM;
+ reg_data->address_info.iProtocol = BTHPROTO_RFCOMM;
+
+ base::string16 cannonical_uuid = L"{" + base::ASCIIToUTF16(
+ uuid.canonical_value()) + L"}";
+ if (!SUCCEEDED(CLSIDFromString(cannonical_uuid.c_str(), &reg_data->uuid))) {
+ LOG(WARNING) << "Failed to start service: "
+ << ", bad uuid=" << cannonical_uuid;
+ PostErrorCompletion(error_callback, kBadUuid);
+ return;
+ }
+
+ reg_data->service.dwSize = sizeof(WSAQUERYSET);
+ reg_data->service.lpszServiceInstanceName =
+ const_cast<LPWSTR>(reg_data->name.c_str());
+ reg_data->service.lpServiceClassId = &reg_data->uuid;
+ reg_data->service.dwNameSpace = NS_BTH;
+ reg_data->service.dwNumberOfCsAddrs = 1;
+ reg_data->service.lpcsaBuffer = &reg_data->address_info;
+
+ if (WSASetService(&reg_data->service,
+ RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) {
+ LOG(WARNING) << "Failed to register profile: WSASetService"
+ << "winsock err=" << WSAGetLastError();
+ PostErrorCompletion(error_callback, kWsaSetServiceError);
+ return;
+ }
+
+ tcp_socket_ = scoped_socket.Pass();
+ service_reg_data_ = reg_data.Pass();
+ on_new_connection_callback_ = new_connection_callback;
+ DoAccept();
+
+ PostSuccess(success_callback);
+}
+
+void BluetoothSocketWin::DoAccept() {
+ DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
+ int result = tcp_socket_->Accept(
+ &accept_socket_,
+ &accept_address_,
+ base::Bind(&BluetoothSocketWin::OnAcceptOnSocketThread, this));
+ if (result != net::OK && result != net::ERR_IO_PENDING)
+ LOG(WARNING) << "Failed to accept, net err=" << result;
+}
+
+void BluetoothSocketWin::OnAcceptOnSocketThread(int accept_result) {
+ DCHECK(socket_thread_->task_runner()->RunsTasksOnCurrentThread());
+ if (accept_result != net::OK) {
+ LOG(WARNING) << "OnAccept error, net err=" << accept_result;
+ return;
+ }
+
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothSocketWin::OnAcceptOnUI,
+ this,
+ base::Passed(&accept_socket_),
+ accept_address_));
+ DoAccept();
+}
+
+void BluetoothSocketWin::OnAcceptOnUI(
+ scoped_ptr<net::TCPSocket> accept_socket,
+ const net::IPEndPoint& peer_address) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+
+ scoped_refptr<BluetoothSocketWin> peer = CreateBluetoothSocket(
+ ui_task_runner_,
+ socket_thread_,
+ net_log_,
+ source_);
+ peer->tcp_socket_ = accept_socket.Pass();
+
+ on_new_connection_callback_.Run(peer, peer_address);
+}
+
} // namespace device
diff --git a/device/bluetooth/bluetooth_socket_win.h b/device/bluetooth/bluetooth_socket_win.h
index 4b09832..0b4ac90 100644
--- a/device/bluetooth/bluetooth_socket_win.h
+++ b/device/bluetooth/bluetooth_socket_win.h
@@ -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);
};
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 3694ea8..b08dbfa 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -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|.
}
diff --git a/net/base/net_util.h b/net/base/net_util.h
index ad0c67a..5556f5e 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -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;
diff --git a/net/socket/tcp_socket_unittest.cc b/net/socket/tcp_socket_unittest.cc
index a45fcba..1981388 100644
--- a/net/socket/tcp_socket_unittest.cc
+++ b/net/socket/tcp_socket_unittest.cc
@@ -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) {
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index 0d1192d..4667bd8 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -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);
diff --git a/net/socket/tcp_socket_win.h b/net/socket/tcp_socket_win.h
index f886d33..2ddd538 100644
--- a/net/socket/tcp_socket_win.h
+++ b/net/socket/tcp_socket_win.h
@@ -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);