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.
5 #include "extensions/browser/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
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"
13 namespace extensions
{
16 using content::BrowserThread
;
18 static base::LazyInstance
<
19 BrowserContextKeyedAPIFactory
<TCPServerSocketEventDispatcher
> > g_factory
=
20 LAZY_INSTANCE_INITIALIZER
;
23 BrowserContextKeyedAPIFactory
<TCPServerSocketEventDispatcher
>*
24 TCPServerSocketEventDispatcher::GetFactoryInstance() {
25 return g_factory
.Pointer();
29 TCPServerSocketEventDispatcher
* TCPServerSocketEventDispatcher::Get(
30 content::BrowserContext
* context
) {
31 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
33 return BrowserContextKeyedAPIFactory
<TCPServerSocketEventDispatcher
>::Get(
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_
;
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_
;
59 TCPServerSocketEventDispatcher::~TCPServerSocketEventDispatcher() {}
61 TCPServerSocketEventDispatcher::AcceptParams::AcceptParams() {}
63 TCPServerSocketEventDispatcher::AcceptParams::~AcceptParams() {}
65 void TCPServerSocketEventDispatcher::OnServerSocketListen(
66 const std::string
& extension_id
,
68 DCHECK_CURRENTLY_ON(thread_id_
);
70 StartSocketAccept(extension_id
, socket_id
);
73 void TCPServerSocketEventDispatcher::OnServerSocketResume(
74 const std::string
& extension_id
,
76 DCHECK_CURRENTLY_ON(thread_id_
);
78 StartSocketAccept(extension_id
, socket_id
);
81 void TCPServerSocketEventDispatcher::StartSocketAccept(
82 const std::string
& extension_id
,
84 DCHECK_CURRENTLY_ON(thread_id_
);
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
;
98 void TCPServerSocketEventDispatcher::StartAccept(const AcceptParams
& params
) {
99 DCHECK_CURRENTLY_ON(params
.thread_id
);
101 ResumableTCPServerSocket
* socket
=
102 params
.server_sockets
->Get(params
.extension_id
, params
.socket_id
);
104 // This can happen if the socket is closed while our callback is active.
107 DCHECK(params
.extension_id
== socket
->owner_extension_id())
108 << "Socket has wrong owner.";
110 // Don't start another accept if the socket has been paused.
111 if (socket
->paused())
115 base::Bind(&TCPServerSocketEventDispatcher::AcceptCallback
, params
));
119 void TCPServerSocketEventDispatcher::AcceptCallback(
120 const AcceptParams
& params
,
122 net::TCPClientSocket
* socket
) {
123 DCHECK_CURRENTLY_ON(params
.thread_id
);
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
);
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());
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(
146 base::Bind(&TCPServerSocketEventDispatcher::StartAccept
, params
));
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());
159 // Since we got an error, the socket is now "paused" until the application
161 ResumableTCPServerSocket
* socket
=
162 params
.server_sockets
->Get(params
.extension_id
, params
.socket_id
);
164 socket
->set_paused(true);
170 void TCPServerSocketEventDispatcher::PostEvent(const AcceptParams
& params
,
171 scoped_ptr
<Event
> event
) {
172 DCHECK_CURRENTLY_ON(params
.thread_id
);
174 BrowserThread::PostTask(BrowserThread::UI
,
176 base::Bind(&DispatchEvent
,
177 params
.browser_context_id
,
179 base::Passed(event
.Pass())));
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
);
189 content::BrowserContext
* context
=
190 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
191 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
193 EventRouter
* router
= EventRouter::Get(context
);
195 router
->DispatchEventToExtension(extension_id
, event
.Pass());
198 } // namespace core_api
199 } // namespace extensions