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