OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/api/bluetooth/bluetooth_socket_event_dispatc
her.h" |
| 6 |
| 7 #include "chrome/browser/browser_process.h" |
| 8 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h" |
| 9 #include "chrome/common/extensions/api/bluetooth.h" |
| 10 #include "extensions/browser/event_router.h" |
| 11 #include "extensions/browser/extension_system.h" |
| 12 #include "net/base/io_buffer.h" |
| 13 #include "net/base/net_errors.h" |
| 14 |
| 15 namespace { |
| 16 |
| 17 namespace bluetooth = extensions::api::bluetooth; |
| 18 using extensions::BluetoothApiSocket; |
| 19 |
| 20 int kDefaultBufferSize = 4096; |
| 21 |
| 22 bluetooth::ReceiveError MapErrorReason(BluetoothApiSocket::ErrorReason value) { |
| 23 switch (value) { |
| 24 case BluetoothApiSocket::kDisconnected: |
| 25 return bluetooth::RECEIVE_ERROR_DISCONNECTED; |
| 26 case BluetoothApiSocket::kIOPending: |
| 27 // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher |
| 28 // handles this specific error. |
| 29 // fallthrough |
| 30 default: |
| 31 return bluetooth::RECEIVE_ERROR_SYSTEM_ERROR; |
| 32 } |
| 33 } |
| 34 |
| 35 } // namespace |
| 36 |
| 37 namespace extensions { |
| 38 namespace api { |
| 39 |
| 40 using content::BrowserThread; |
| 41 |
| 42 BluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher( |
| 43 content::BrowserContext* context, |
| 44 scoped_refptr<SocketData> socket_data) |
| 45 : thread_id_(BluetoothApiSocket::kThreadId), |
| 46 browser_context_id_(context), |
| 47 socket_data_(socket_data) {} |
| 48 |
| 49 BluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {} |
| 50 |
| 51 BluetoothSocketEventDispatcher::ReceiveParams::ReceiveParams() {} |
| 52 |
| 53 BluetoothSocketEventDispatcher::ReceiveParams::~ReceiveParams() {} |
| 54 |
| 55 void BluetoothSocketEventDispatcher::OnSocketResume( |
| 56 const std::string& extension_id, |
| 57 int socket_id) { |
| 58 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 59 |
| 60 ReceiveParams params; |
| 61 params.extension_id = extension_id; |
| 62 params.socket_id = socket_id; |
| 63 StartReceive(params); |
| 64 } |
| 65 |
| 66 void BluetoothSocketEventDispatcher::StartReceive(const ReceiveParams& params) { |
| 67 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 68 |
| 69 BluetoothApiSocket* socket = |
| 70 socket_data_->Get(params.extension_id, params.socket_id); |
| 71 if (!socket) { |
| 72 // This can happen if the socket is closed while our callback is active. |
| 73 return; |
| 74 } |
| 75 DCHECK(params.extension_id == socket->owner_extension_id()) |
| 76 << "Socket has wrong owner."; |
| 77 |
| 78 // Don't start another read if the socket has been paused. |
| 79 if (socket->paused()) |
| 80 return; |
| 81 |
| 82 int buffer_size = socket->buffer_size(); |
| 83 if (buffer_size <= 0) |
| 84 buffer_size = kDefaultBufferSize; |
| 85 socket->Receive( |
| 86 buffer_size, |
| 87 base::Bind( |
| 88 &BluetoothSocketEventDispatcher::ReceiveCallback, this, params), |
| 89 base::Bind( |
| 90 &BluetoothSocketEventDispatcher::ReceiveErrorCallback, this, params)); |
| 91 } |
| 92 |
| 93 void BluetoothSocketEventDispatcher::ReceiveCallback( |
| 94 const ReceiveParams& params, |
| 95 int bytes_read, |
| 96 scoped_refptr<net::IOBuffer> io_buffer) { |
| 97 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 98 |
| 99 // Dispatch "onReceive" event. |
| 100 bluetooth::ReceiveInfo receive_info; |
| 101 receive_info.socket_id = params.socket_id; |
| 102 receive_info.data = std::string(io_buffer->data(), bytes_read); |
| 103 scoped_ptr<base::ListValue> args = bluetooth::OnReceive::Create(receive_info); |
| 104 scoped_ptr<Event> event( |
| 105 new Event(bluetooth::OnReceive::kEventName, args.Pass())); |
| 106 PostEvent(params, event.Pass()); |
| 107 |
| 108 // Post a task to delay the read until the socket is available, as |
| 109 // calling StartReceive at this point would error with ERR_IO_PENDING. |
| 110 BrowserThread::PostTask( |
| 111 thread_id_, |
| 112 FROM_HERE, |
| 113 base::Bind(&BluetoothSocketEventDispatcher::StartReceive, this, params)); |
| 114 } |
| 115 |
| 116 void BluetoothSocketEventDispatcher::ReceiveErrorCallback( |
| 117 const ReceiveParams& params, |
| 118 BluetoothApiSocket::ErrorReason error_reason, |
| 119 const std::string& error) { |
| 120 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 121 |
| 122 if (error_reason == BluetoothApiSocket::kIOPending) { |
| 123 // This happens when resuming a socket which already had an active "read" |
| 124 // callback. We can safely ignore this error, as the application should not |
| 125 // care. |
| 126 return; |
| 127 } |
| 128 |
| 129 // Dispatch "onReceiveError" event but don't start another read to avoid |
| 130 // potential infinite reads if we have a persistent network error. |
| 131 bluetooth::ReceiveErrorInfo receive_error_info; |
| 132 receive_error_info.socket_id = params.socket_id; |
| 133 receive_error_info.error_message = error; |
| 134 receive_error_info.error = MapErrorReason(error_reason); |
| 135 scoped_ptr<base::ListValue> args = |
| 136 bluetooth::OnReceiveError::Create(receive_error_info); |
| 137 scoped_ptr<Event> event( |
| 138 new Event(bluetooth::OnReceiveError::kEventName, args.Pass())); |
| 139 PostEvent(params, event.Pass()); |
| 140 |
| 141 // Since we got an error, the socket is now "paused" until the application |
| 142 // "resumes" it. |
| 143 BluetoothApiSocket* socket = |
| 144 socket_data_->Get(params.extension_id, params.socket_id); |
| 145 if (socket) { |
| 146 socket->set_paused(true); |
| 147 } |
| 148 } |
| 149 |
| 150 void BluetoothSocketEventDispatcher::PostEvent(const ReceiveParams& params, |
| 151 scoped_ptr<Event> event) { |
| 152 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); |
| 153 |
| 154 BrowserThread::PostTask( |
| 155 BrowserThread::UI, |
| 156 FROM_HERE, |
| 157 base::Bind(&BluetoothSocketEventDispatcher::DispatchEvent, |
| 158 this, |
| 159 params.extension_id, |
| 160 base::Passed(event.Pass()))); |
| 161 } |
| 162 |
| 163 void BluetoothSocketEventDispatcher::DispatchEvent( |
| 164 const std::string& extension_id, |
| 165 scoped_ptr<Event> event) { |
| 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 167 |
| 168 content::BrowserContext* context = |
| 169 reinterpret_cast<content::BrowserContext*>(browser_context_id_); |
| 170 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) |
| 171 return; |
| 172 |
| 173 EventRouter* router = ExtensionSystem::Get(context)->event_router(); |
| 174 if (router) |
| 175 router->DispatchEventToExtension(extension_id, event.Pass()); |
| 176 } |
| 177 |
| 178 } // namespace api |
| 179 } // namespace extensions |
OLD | NEW |