diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-29 10:24:35 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-29 10:24:35 +0000 |
commit | ef2f002744fa3b40f0da96b959b5defa0dd2f565 (patch) | |
tree | 24d0e4f30c84811887d0877156a3cca98bc33854 | |
parent | 3c05331313cf4d8569b656ced2e09ed2ed3cdbb4 (diff) | |
download | chromium_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.h | 7 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_profile.cc | 6 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_profile_win.cc | 113 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_profile_win.h | 44 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_socket_win.cc | 227 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_socket_win.h | 40 | ||||
-rw-r--r-- | net/base/net_util.cc | 17 | ||||
-rw-r--r-- | net/base/net_util.h | 4 | ||||
-rw-r--r-- | net/socket/tcp_socket_unittest.cc | 55 | ||||
-rw-r--r-- | net/socket/tcp_socket_win.cc | 18 | ||||
-rw-r--r-- | net/socket/tcp_socket_win.h | 7 |
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*>(®_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 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 = ®_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(); + 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); |