Index: device/bluetooth/bluetooth_profile_win.cc |
diff --git a/device/bluetooth/bluetooth_profile_win.cc b/device/bluetooth/bluetooth_profile_win.cc |
index 79848caf074fc2a931b307695e946dca9f8bde09..79dc561b2012f632beceffd16c208ecd856dfeaa 100644 |
--- a/device/bluetooth/bluetooth_profile_win.cc |
+++ b/device/bluetooth/bluetooth_profile_win.cc |
@@ -4,14 +4,23 @@ |
#include "device/bluetooth/bluetooth_profile_win.h" |
+#include <objbase.h> |
+ |
#include "base/bind.h" |
+#include "base/logging.h" |
#include "base/memory/ref_counted.h" |
#include "base/sequenced_task_runner.h" |
+#include "base/strings/string16.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/utf_string_conversions.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" |
#include "device/bluetooth/bluetooth_socket_win.h" |
+#include "net/base/net_errors.h" |
+#include "net/socket/tcp_socket.h" |
namespace { |
@@ -62,19 +71,56 @@ void OnConnectErrorUI(scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
error_callback.Run(error); |
} |
+std::string IPEndPointToBluetoothAddress(const net::IPEndPoint& end_point) { |
+ const size_t kBtAddressSize = 6; |
+ if (end_point.address().size() != kBtAddressSize) |
+ return std::string(); |
+ 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) { |
+struct BluetoothProfileWin::ProfileRegData { |
+ ProfileRegData() { |
+ ZeroMemory(this, sizeof(ProfileRegData)); |
+ } |
+ |
+ SOCKADDR_BTH address; |
+ CSADDR_INFO address_info; |
+ GUID uuid; |
+ base::string16 name; |
+ WSAQUERYSET service; |
+}; |
+ |
+BluetoothProfileWin::BluetoothProfileWin() |
+ : BluetoothProfile(), rfcomm_channel_(0), weak_ptr_factory_(this) { |
} |
BluetoothProfileWin::~BluetoothProfileWin() { |
} |
void BluetoothProfileWin::Unregister() { |
+ if (adapter_) { |
+ if (profile_reg_data_) { |
+ adapter()->socket_thread()->task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&BluetoothProfileWin::UnregisterProfileOnSocketThread, |
+ base::Passed(&profile_reg_data_))); |
+ } |
+ if (profile_socket_) |
+ profile_socket_->Close(); |
+ |
+ adapter()->socket_thread()->OnSocketDeactivate(); |
+ } |
+ |
delete this; |
} |
@@ -83,6 +129,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, |
@@ -116,4 +175,197 @@ void BluetoothProfileWin::Connect( |
error_callback); |
} |
+void BluetoothProfileWin::OnGetAdapter( |
+ const ProfileCallback& callback, |
+ scoped_refptr<BluetoothAdapter> in_adapter) { |
+ DCHECK(!adapter_); |
+ DCHECK(!profile_socket_); |
+ DCHECK(!profile_reg_data_); |
+ |
+ adapter_ = in_adapter; |
+ adapter()->socket_thread()->OnSocketActivate(); |
+ |
+ // The followings are owned by register profile reply callback. |
+ bool* success = new bool(false); |
+ scoped_ptr<net::TCPSocket>* socket = new scoped_ptr<net::TCPSocket>; |
+ scoped_ptr<ProfileRegData>* reg_data = new scoped_ptr<ProfileRegData>; |
+ |
+ adapter()->socket_thread()->task_runner() |
+ ->PostTaskAndReply( |
+ FROM_HERE, |
+ base::Bind(&BluetoothProfileWin::RegisterProfileOnSocketThread, |
+ uuid_, |
+ name_, |
+ rfcomm_channel_, |
+ success, |
+ socket, |
+ reg_data), |
+ base::Bind(&BluetoothProfileWin::OnRegisterProfileOnUI, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ base::Owned(success), |
+ base::Owned(socket), |
+ base::Owned(reg_data), |
+ callback)); |
+} |
+ |
+// static |
+void BluetoothProfileWin::RegisterProfileOnSocketThread( |
+ const device::BluetoothUUID& uuid, |
+ const std::string& name, |
+ int rfcomm_channel, |
+ bool* out_success, |
+ scoped_ptr<net::TCPSocket>* out_socket, |
+ scoped_ptr<ProfileRegData>* out_reg_data) { |
+ *out_success = false; |
+ |
+ // 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 register profile: " |
+ << "Invalid RFCCOMM port " << rfcomm_channel |
+ << ", uuid=" << uuid.value(); |
+ return; |
+ } |
+ |
+ SOCKET socket_fd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); |
+ if (socket_fd == INVALID_SOCKET) { |
+ LOG(WARNING) << "Failed to register profile: create socket, " |
+ << "winsock err=" << WSAGetLastError(); |
+ return; |
+ } |
+ |
+ scoped_ptr<net::TCPSocket> scoped_socket( |
+ new net::TCPSocket(NULL, net::NetLog::Source())); |
+ scoped_socket->AdoptBoundSocket(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 register profile: create socket, " |
+ << "winsock err=" << WSAGetLastError(); |
+ return; |
+ } |
+ |
+ const int kListenBacklog = 5; |
+ if (scoped_socket->Listen(kListenBacklog) < 0) { |
+ LOG(WARNING) << "Failed to register profile: Listen" |
+ << "winsock err=" << WSAGetLastError(); |
+ return; |
+ } |
+ |
+ scoped_ptr<ProfileRegData> reg_data(new ProfileRegData); |
+ reg_data->name = base::UTF8ToUTF16(name); |
+ |
+ if (getsockname(socket_fd, sock_addr, &sock_addr_len)) { |
+ LOG(WARNING) << "Failed to register profile: getsockname, " |
+ << "winsock err=" << WSAGetLastError(); |
+ return; |
+ } |
+ reg_data->address = sa; |
+ |
+ reg_data->address_info.LocalAddr.iSockaddrLength = sizeof(sa); |
+ reg_data->address_info.LocalAddr.lpSockaddr = |
+ reinterpret_cast<struct sockaddr*>(®_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(), ®_data->uuid))) { |
+ LOG(WARNING) << "Failed to register profile: " |
+ << ", bad uuid=" << cannonical_uuid; |
+ return; |
+ } |
+ |
+ reg_data->service.dwSize = sizeof(WSAQUERYSET); |
+ reg_data->service.lpszServiceInstanceName = |
+ const_cast<LPWSTR>(reg_data->name.c_str()); |
+ reg_data->service.lpServiceClassId = ®_data->uuid; |
+ reg_data->service.dwNameSpace = NS_BTH; |
+ reg_data->service.dwNumberOfCsAddrs = 1; |
+ reg_data->service.lpcsaBuffer = ®_data->address_info; |
+ |
+ if (WSASetService(®_data->service, |
+ RNRSERVICE_REGISTER, 0) == SOCKET_ERROR) { |
+ LOG(WARNING) << "Failed to register profile: WSASetService" |
+ << "winsock err=" << WSAGetLastError(); |
+ return; |
+ } |
+ |
+ *out_socket = scoped_socket.Pass(); |
+ *out_reg_data = reg_data.Pass(); |
+ *out_success = true; |
+} |
+ |
+void BluetoothProfileWin::OnRegisterProfileOnUI( |
+ bool* success, |
+ scoped_ptr<net::TCPSocket>* socket, |
+ scoped_ptr<ProfileRegData>* reg_data, |
+ const ProfileCallback& callback) { |
+ DCHECK(adapter()->ui_task_runner()->RunsTasksOnCurrentThread()); |
+ |
+ if (!(*success)) { |
+ callback.Run(NULL); |
+ delete this; |
+ return; |
+ } |
+ |
+ DCHECK(*socket); |
+ DCHECK(*reg_data); |
+ |
+ profile_socket_ = BluetoothSocketWin::CreateBluetoothSocket( |
+ socket->Pass(), |
+ adapter()->ui_task_runner(), |
+ adapter()->socket_thread(), |
+ NULL, |
+ net::NetLog::Source()); |
+ profile_reg_data_ = reg_data->Pass(); |
+ |
+ profile_socket_->Accept(base::Bind(&BluetoothProfileWin::OnNewConnection, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ callback.Run(this); |
+} |
+ |
+// static |
+void BluetoothProfileWin::UnregisterProfileOnSocketThread( |
+ scoped_ptr<BluetoothProfileWin::ProfileRegData> reg_data) { |
+ if (WSASetService(®_data->service,RNRSERVICE_DELETE, 0) == SOCKET_ERROR) |
+ LOG(WARNING) << "Failed to unregister profile"; |
+} |
+ |
+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 |