Home | History | Annotate | Download | only in sockets_tcp_server
      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 "extensions/browser/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "extensions/browser/api/socket/tcp_socket.h"
      9 #include "extensions/browser/event_router.h"
     10 #include "extensions/browser/extensions_browser_client.h"
     11 #include "net/base/net_errors.h"
     12 
     13 namespace extensions {
     14 namespace core_api {
     15 
     16 using content::BrowserThread;
     17 
     18 static base::LazyInstance<
     19     BrowserContextKeyedAPIFactory<TCPServerSocketEventDispatcher> > g_factory =
     20     LAZY_INSTANCE_INITIALIZER;
     21 
     22 // static
     23 BrowserContextKeyedAPIFactory<TCPServerSocketEventDispatcher>*
     24 TCPServerSocketEventDispatcher::GetFactoryInstance() {
     25   return g_factory.Pointer();
     26 }
     27 
     28 // static
     29 TCPServerSocketEventDispatcher* TCPServerSocketEventDispatcher::Get(
     30     content::BrowserContext* context) {
     31   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     32 
     33   return BrowserContextKeyedAPIFactory<TCPServerSocketEventDispatcher>::Get(
     34       context);
     35 }
     36 
     37 TCPServerSocketEventDispatcher::TCPServerSocketEventDispatcher(
     38     content::BrowserContext* context)
     39     : thread_id_(Socket::kThreadId), browser_context_(context) {
     40   ApiResourceManager<ResumableTCPServerSocket>* server_manager =
     41       ApiResourceManager<ResumableTCPServerSocket>::Get(browser_context_);
     42   DCHECK(server_manager)
     43       << "There is no server socket manager. "
     44          "If this assertion is failing during a test, then it is likely that "
     45          "TestExtensionSystem is failing to provide an instance of "
     46          "ApiResourceManager<ResumableTCPServerSocket>.";
     47   server_sockets_ = server_manager->data_;
     48 
     49   ApiResourceManager<ResumableTCPSocket>* client_manager =
     50       ApiResourceManager<ResumableTCPSocket>::Get(browser_context_);
     51   DCHECK(client_manager)
     52       << "There is no client socket manager. "
     53          "If this assertion is failing during a test, then it is likely that "
     54          "TestExtensionSystem is failing to provide an instance of "
     55          "ApiResourceManager<ResumableTCPSocket>.";
     56   client_sockets_ = client_manager->data_;
     57 }
     58 
     59 TCPServerSocketEventDispatcher::~TCPServerSocketEventDispatcher() {}
     60 
     61 TCPServerSocketEventDispatcher::AcceptParams::AcceptParams() {}
     62 
     63 TCPServerSocketEventDispatcher::AcceptParams::~AcceptParams() {}
     64 
     65 void TCPServerSocketEventDispatcher::OnServerSocketListen(
     66     const std::string& extension_id,
     67     int socket_id) {
     68   DCHECK_CURRENTLY_ON(thread_id_);
     69 
     70   StartSocketAccept(extension_id, socket_id);
     71 }
     72 
     73 void TCPServerSocketEventDispatcher::OnServerSocketResume(
     74     const std::string& extension_id,
     75     int socket_id) {
     76   DCHECK_CURRENTLY_ON(thread_id_);
     77 
     78   StartSocketAccept(extension_id, socket_id);
     79 }
     80 
     81 void TCPServerSocketEventDispatcher::StartSocketAccept(
     82     const std::string& extension_id,
     83     int socket_id) {
     84   DCHECK_CURRENTLY_ON(thread_id_);
     85 
     86   AcceptParams params;
     87   params.thread_id = thread_id_;
     88   params.browser_context_id = browser_context_;
     89   params.extension_id = extension_id;
     90   params.server_sockets = server_sockets_;
     91   params.client_sockets = client_sockets_;
     92   params.socket_id = socket_id;
     93 
     94   StartAccept(params);
     95 }
     96 
     97 // static
     98 void TCPServerSocketEventDispatcher::StartAccept(const AcceptParams& params) {
     99   DCHECK_CURRENTLY_ON(params.thread_id);
    100 
    101   ResumableTCPServerSocket* socket =
    102       params.server_sockets->Get(params.extension_id, params.socket_id);
    103   if (!socket) {
    104     // This can happen if the socket is closed while our callback is active.
    105     return;
    106   }
    107   DCHECK(params.extension_id == socket->owner_extension_id())
    108       << "Socket has wrong owner.";
    109 
    110   // Don't start another accept if the socket has been paused.
    111   if (socket->paused())
    112     return;
    113 
    114   socket->Accept(
    115       base::Bind(&TCPServerSocketEventDispatcher::AcceptCallback, params));
    116 }
    117 
    118 // static
    119 void TCPServerSocketEventDispatcher::AcceptCallback(
    120     const AcceptParams& params,
    121     int result_code,
    122     net::TCPClientSocket* socket) {
    123   DCHECK_CURRENTLY_ON(params.thread_id);
    124 
    125   if (result_code >= 0) {
    126     ResumableTCPSocket* client_socket =
    127         new ResumableTCPSocket(socket, params.extension_id, true);
    128     client_socket->set_paused(true);
    129     int client_socket_id = params.client_sockets->Add(client_socket);
    130 
    131     // Dispatch "onAccept" event.
    132     sockets_tcp_server::AcceptInfo accept_info;
    133     accept_info.socket_id = params.socket_id;
    134     accept_info.client_socket_id = client_socket_id;
    135     scoped_ptr<base::ListValue> args =
    136         sockets_tcp_server::OnAccept::Create(accept_info);
    137     scoped_ptr<Event> event(
    138         new Event(sockets_tcp_server::OnAccept::kEventName, args.Pass()));
    139     PostEvent(params, event.Pass());
    140 
    141     // Post a task to delay the "accept" until the socket is available, as
    142     // calling StartAccept at this point would error with ERR_IO_PENDING.
    143     BrowserThread::PostTask(
    144         params.thread_id,
    145         FROM_HERE,
    146         base::Bind(&TCPServerSocketEventDispatcher::StartAccept, params));
    147   } else {
    148     // Dispatch "onAcceptError" event but don't start another accept to avoid
    149     // potential infinite "accepts" if we have a persistent network error.
    150     sockets_tcp_server::AcceptErrorInfo accept_error_info;
    151     accept_error_info.socket_id = params.socket_id;
    152     accept_error_info.result_code = result_code;
    153     scoped_ptr<base::ListValue> args =
    154         sockets_tcp_server::OnAcceptError::Create(accept_error_info);
    155     scoped_ptr<Event> event(
    156         new Event(sockets_tcp_server::OnAcceptError::kEventName, args.Pass()));
    157     PostEvent(params, event.Pass());
    158 
    159     // Since we got an error, the socket is now "paused" until the application
    160     // "resumes" it.
    161     ResumableTCPServerSocket* socket =
    162         params.server_sockets->Get(params.extension_id, params.socket_id);
    163     if (socket) {
    164       socket->set_paused(true);
    165     }
    166   }
    167 }
    168 
    169 // static
    170 void TCPServerSocketEventDispatcher::PostEvent(const AcceptParams& params,
    171                                                scoped_ptr<Event> event) {
    172   DCHECK_CURRENTLY_ON(params.thread_id);
    173 
    174   BrowserThread::PostTask(BrowserThread::UI,
    175                           FROM_HERE,
    176                           base::Bind(&DispatchEvent,
    177                                      params.browser_context_id,
    178                                      params.extension_id,
    179                                      base::Passed(event.Pass())));
    180 }
    181 
    182 // static
    183 void TCPServerSocketEventDispatcher::DispatchEvent(
    184     void* browser_context_id,
    185     const std::string& extension_id,
    186     scoped_ptr<Event> event) {
    187   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    188 
    189   content::BrowserContext* context =
    190       reinterpret_cast<content::BrowserContext*>(browser_context_id);
    191   if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
    192     return;
    193   EventRouter* router = EventRouter::Get(context);
    194   if (router)
    195     router->DispatchEventToExtension(extension_id, event.Pass());
    196 }
    197 
    198 }  // namespace core_api
    199 }  // namespace extensions
    200