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(new Event(events::SOCKETS_TCP_SERVER_ON_ACCEPT
,
138 sockets_tcp_server::OnAccept::kEventName
,
140 PostEvent(params
, event
.Pass());
142 // Post a task to delay the "accept" until the socket is available, as
143 // calling StartAccept at this point would error with ERR_IO_PENDING.
144 BrowserThread::PostTask(
147 base::Bind(&TCPServerSocketEventDispatcher::StartAccept
, params
));
149 // Dispatch "onAcceptError" event but don't start another accept to avoid
150 // potential infinite "accepts" if we have a persistent network error.
151 sockets_tcp_server::AcceptErrorInfo accept_error_info
;
152 accept_error_info
.socket_id
= params
.socket_id
;
153 accept_error_info
.result_code
= result_code
;
154 scoped_ptr
<base::ListValue
> args
=
155 sockets_tcp_server::OnAcceptError::Create(accept_error_info
);
156 scoped_ptr
<Event
> event(
157 new Event(events::SOCKETS_TCP_SERVER_ON_ACCEPT_ERROR
,
158 sockets_tcp_server::OnAcceptError::kEventName
, args
.Pass()));
159 PostEvent(params
, event
.Pass());
161 // Since we got an error, the socket is now "paused" until the application
163 ResumableTCPServerSocket
* socket
=
164 params
.server_sockets
->Get(params
.extension_id
, params
.socket_id
);
166 socket
->set_paused(true);
172 void TCPServerSocketEventDispatcher::PostEvent(const AcceptParams
& params
,
173 scoped_ptr
<Event
> event
) {
174 DCHECK_CURRENTLY_ON(params
.thread_id
);
176 BrowserThread::PostTask(BrowserThread::UI
,
178 base::Bind(&DispatchEvent
,
179 params
.browser_context_id
,
181 base::Passed(event
.Pass())));
185 void TCPServerSocketEventDispatcher::DispatchEvent(
186 void* browser_context_id
,
187 const std::string
& extension_id
,
188 scoped_ptr
<Event
> event
) {
189 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
191 content::BrowserContext
* context
=
192 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
193 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
195 EventRouter
* router
= EventRouter::Get(context
);
197 router
->DispatchEventToExtension(extension_id
, event
.Pass());
201 } // namespace extensions