1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// found in the LICENSE file.
4c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
6c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/lazy_instance.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_device.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_socket.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_socket/bluetooth_api_socket.h"
11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/browser/event_router.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/api/bluetooth_socket.h"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/io_buffer.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace {
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace bluetooth_socket = extensions::core_api::bluetooth_socket;
18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing extensions::BluetoothApiSocket;
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint kDefaultBufferSize = 4096;
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bluetooth_socket::ReceiveError MapReceiveErrorReason(
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    BluetoothApiSocket::ErrorReason value) {
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  switch (value) {
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case BluetoothApiSocket::kDisconnected:
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return bluetooth_socket::RECEIVE_ERROR_DISCONNECTED;
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case BluetoothApiSocket::kNotConnected:
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // kNotConnected is impossible since a socket has to be connected to be
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // able to call Receive() on it.
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // fallthrough
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case BluetoothApiSocket::kIOPending:
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // kIOPending is not relevant to apps, as BluetoothSocketEventDispatcher
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // handles this specific error.
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // fallthrough
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    default:
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return bluetooth_socket::RECEIVE_ERROR_SYSTEM_ERROR;
37c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bluetooth_socket::AcceptError MapAcceptErrorReason(
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BluetoothApiSocket::ErrorReason value) {
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // TODO(keybuk): All values are system error, we may want to seperate these
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // out to more discrete reasons.
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  switch (value) {
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case BluetoothApiSocket::kNotListening:
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // kNotListening is impossible since a socket has to be listening to be
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // able to call Accept() on it.
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // fallthrough
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    default:
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return bluetooth_socket::ACCEPT_ERROR_SYSTEM_ERROR;
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace
55c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochnamespace extensions {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace core_api {
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochusing content::BrowserThread;
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustatic base::LazyInstance<
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher> > g_factory =
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    LAZY_INSTANCE_INITIALIZER;
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>*
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothSocketEventDispatcher::GetFactoryInstance() {
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return g_factory.Pointer();
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothSocketEventDispatcher* BluetoothSocketEventDispatcher::Get(
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content::BrowserContext* context) {
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_CURRENTLY_ON(BrowserThread::UI);
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return BrowserContextKeyedAPIFactory<BluetoothSocketEventDispatcher>::Get(
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      context);
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothSocketEventDispatcher::BluetoothSocketEventDispatcher(
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content::BrowserContext* context)
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : thread_id_(BluetoothApiSocket::kThreadId),
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      browser_context_(context) {
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ApiResourceManager<BluetoothApiSocket>* manager =
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ApiResourceManager<BluetoothApiSocket>::Get(browser_context_);
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(manager)
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      << "There is no socket manager. "
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         "If this assertion is failing during a test, then it is likely that "
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         "TestExtensionSystem is failing to provide an instance of "
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu         "ApiResourceManager<BluetoothApiSocket>.";
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  sockets_ = manager->data_;
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochBluetoothSocketEventDispatcher::~BluetoothSocketEventDispatcher() {}
95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BluetoothSocketEventDispatcher::SocketParams::SocketParams() {}
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BluetoothSocketEventDispatcher::SocketParams::~SocketParams() {}
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketConnect(
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& extension_id,
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int socket_id) {
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(thread_id_));
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SocketParams params;
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.thread_id = thread_id_;
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.browser_context_id = browser_context_;
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.extension_id = extension_id;
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.sockets = sockets_;
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.socket_id = socket_id;
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  StartReceive(params);
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketListen(
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id,
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int socket_id) {
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(thread_id_));
119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SocketParams params;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.thread_id = thread_id_;
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.browser_context_id = browser_context_;
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.extension_id = extension_id;
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.sockets = sockets_;
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  params.socket_id = socket_id;
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  StartAccept(params);
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::OnSocketResume(
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& extension_id,
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int socket_id) {
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(thread_id_));
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SocketParams params;
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  params.thread_id = thread_id_;
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  params.browser_context_id = browser_context_;
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  params.extension_id = extension_id;
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  params.sockets = sockets_;
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  params.socket_id = socket_id;
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothApiSocket* socket =
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.sockets->Get(params.extension_id, params.socket_id);
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!socket) {
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This can happen if the socket is closed while our callback is active.
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (socket->IsConnected()) {
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    StartReceive(params);
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    StartAccept(params);
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::StartReceive(const SocketParams& params) {
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BluetoothApiSocket* socket =
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      params.sockets->Get(params.extension_id, params.socket_id);
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!socket) {
163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // This can happen if the socket is closed while our callback is active.
164c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
166c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(params.extension_id == socket->owner_extension_id())
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      << "Socket has wrong owner.";
168c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Don't start another read if the socket has been paused.
170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (socket->paused())
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int buffer_size = socket->buffer_size();
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (buffer_size <= 0)
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    buffer_size = kDefaultBufferSize;
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  socket->Receive(
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      buffer_size,
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          &BluetoothSocketEventDispatcher::ReceiveCallback, params),
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          &BluetoothSocketEventDispatcher::ReceiveErrorCallback, params));
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::ReceiveCallback(
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SocketParams& params,
187c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int bytes_read,
188c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    scoped_refptr<net::IOBuffer> io_buffer) {
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Dispatch "onReceive" event.
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bluetooth_socket::ReceiveInfo receive_info;
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  receive_info.socket_id = params.socket_id;
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  receive_info.data = std::string(io_buffer->data(), bytes_read);
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<base::ListValue> args =
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      bluetooth_socket::OnReceive::Create(receive_info);
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<Event> event(
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new Event(bluetooth_socket::OnReceive::kEventName, args.Pass()));
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PostEvent(params, event.Pass());
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Post a task to delay the read until the socket is available, as
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // calling StartReceive at this point would error with ERR_IO_PENDING.
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      params.thread_id,
205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&BluetoothSocketEventDispatcher::StartReceive, params));
207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::ReceiveErrorCallback(
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SocketParams& params,
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    BluetoothApiSocket::ErrorReason error_reason,
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& error) {
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (error_reason == BluetoothApiSocket::kIOPending) {
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // This happens when resuming a socket which already had an active "read"
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // callback. We can safely ignore this error, as the application should not
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // care.
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Dispatch "onReceiveError" event but don't start another read to avoid
224c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // potential infinite reads if we have a persistent network error.
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bluetooth_socket::ReceiveErrorInfo receive_error_info;
226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  receive_error_info.socket_id = params.socket_id;
227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  receive_error_info.error_message = error;
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  receive_error_info.error = MapReceiveErrorReason(error_reason);
229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::ListValue> args =
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      bluetooth_socket::OnReceiveError::Create(receive_error_info);
231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<Event> event(
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new Event(bluetooth_socket::OnReceiveError::kEventName, args.Pass()));
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PostEvent(params, event.Pass());
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Since we got an error, the socket is now "paused" until the application
236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // "resumes" it.
237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BluetoothApiSocket* socket =
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      params.sockets->Get(params.extension_id, params.socket_id);
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (socket) {
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    socket->set_paused(true);
241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::StartAccept(const SocketParams& params) {
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothApiSocket* socket =
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.sockets->Get(params.extension_id, params.socket_id);
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!socket) {
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This can happen if the socket is closed while our callback is active.
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(params.extension_id == socket->owner_extension_id())
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      << "Socket has wrong owner.";
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Don't start another accept if the socket has been paused.
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (socket->paused())
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  socket->Accept(
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          &BluetoothSocketEventDispatcher::AcceptCallback, params),
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          &BluetoothSocketEventDispatcher::AcceptErrorCallback, params));
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::AcceptCallback(
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SocketParams& params,
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const device::BluetoothDevice* device,
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<device::BluetoothSocket> socket) {
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothApiSocket* server_api_socket =
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.sockets->Get(params.extension_id, params.socket_id);
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(server_api_socket);
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothApiSocket* client_api_socket = new BluetoothApiSocket(
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.extension_id,
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      socket,
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      device->GetAddress(),
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      server_api_socket->uuid());
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int client_socket_id = params.sockets->Add(client_api_socket);
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Dispatch "onAccept" event.
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bluetooth_socket::AcceptInfo accept_info;
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accept_info.socket_id = params.socket_id;
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accept_info.client_socket_id = client_socket_id;
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::ListValue> args =
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bluetooth_socket::OnAccept::Create(accept_info);
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Event> event(
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new Event(bluetooth_socket::OnAccept::kEventName, args.Pass()));
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PostEvent(params, event.Pass());
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Post a task to delay the accept until the socket is available, as
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // calling StartAccept at this point would error with ERR_IO_PENDING.
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BrowserThread::PostTask(
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.thread_id,
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FROM_HERE,
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&BluetoothSocketEventDispatcher::StartAccept, params));
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::AcceptErrorCallback(
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SocketParams& params,
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BluetoothApiSocket::ErrorReason error_reason,
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& error) {
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (error_reason == BluetoothApiSocket::kIOPending) {
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This happens when resuming a socket which already had an active "accept"
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // callback. We can safely ignore this error, as the application should not
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // care.
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Dispatch "onAcceptError" event but don't start another accept to avoid
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // potential infinite accepts if we have a persistent network error.
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bluetooth_socket::AcceptErrorInfo accept_error_info;
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accept_error_info.socket_id = params.socket_id;
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accept_error_info.error_message = error;
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accept_error_info.error = MapAcceptErrorReason(error_reason);
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::ListValue> args =
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bluetooth_socket::OnAcceptError::Create(accept_error_info);
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Event> event(
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new Event(bluetooth_socket::OnAcceptError::kEventName, args.Pass()));
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PostEvent(params, event.Pass());
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Since we got an error, the socket is now "paused" until the application
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // "resumes" it.
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BluetoothApiSocket* socket =
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      params.sockets->Get(params.extension_id, params.socket_id);
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (socket) {
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    socket->set_paused(true);
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothSocketEventDispatcher::PostEvent(const SocketParams& params,
341c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                               scoped_ptr<Event> event) {
3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
343c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
344c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
345c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::UI,
346c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&DispatchEvent,
3485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 params.browser_context_id,
349c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 params.extension_id,
350c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 base::Passed(event.Pass())));
351c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
352c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid BluetoothSocketEventDispatcher::DispatchEvent(
3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    void* browser_context_id,
356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& extension_id,
357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    scoped_ptr<Event> event) {
358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
360c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  content::BrowserContext* context =
3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      reinterpret_cast<content::BrowserContext*>(browser_context_id);
362c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
364c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter* router = EventRouter::Get(context);
366c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (router)
367c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    router->DispatchEventToExtension(extension_id, event.Pass());
368c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
369c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace core_api
371c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}  // namespace extensions
372