OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.
h" | |
6 | |
7 #include "chrome/browser/extensions/api/socket/udp_socket.h" | |
8 #include "extensions/browser/event_router.h" | |
9 #include "extensions/browser/extension_system.h" | |
10 #include "extensions/browser/extensions_browser_client.h" | |
11 #include "net/base/net_errors.h" | |
12 | |
13 namespace extensions { | |
14 namespace api { | |
15 | |
16 using content::BrowserThread; | |
17 | |
18 static base::LazyInstance< | |
19 BrowserContextKeyedAPIFactory<UDPSocketEventDispatcher> > g_factory = | |
20 LAZY_INSTANCE_INITIALIZER; | |
21 | |
22 // static | |
23 BrowserContextKeyedAPIFactory<UDPSocketEventDispatcher>* | |
24 UDPSocketEventDispatcher::GetFactoryInstance() { | |
25 return g_factory.Pointer(); | |
26 } | |
27 | |
28 // static | |
29 UDPSocketEventDispatcher* UDPSocketEventDispatcher::Get( | |
30 content::BrowserContext* context) { | |
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
32 | |
33 return BrowserContextKeyedAPIFactory<UDPSocketEventDispatcher>::Get(context); | |
34 } | |
35 | |
36 UDPSocketEventDispatcher::UDPSocketEventDispatcher( | |
37 content::BrowserContext* context) | |
38 : thread_id_(Socket::kThreadId), browser_context_(context) { | |
39 ApiResourceManager<ResumableUDPSocket>* manager = | |
40 ApiResourceManager<ResumableUDPSocket>::Get(browser_context_); | |
41 DCHECK(manager) << "There is no socket manager. " | |
42 "If this assertion is failing during a test, then it is likely that " | |
43 "TestExtensionSystem is failing to provide an instance of " | |
44 "ApiResourceManager<ResumableUDPSocket>."; | |
45 sockets_ = manager->data_; | |
46 } | |
47 | |
48 UDPSocketEventDispatcher::~UDPSocketEventDispatcher() {} | |
49 | |
50 UDPSocketEventDispatcher::ReceiveParams::ReceiveParams() {} | |
51 | |
52 UDPSocketEventDispatcher::ReceiveParams::~ReceiveParams() {} | |
53 | |
54 void UDPSocketEventDispatcher::OnSocketBind(const std::string& extension_id, | |
55 int socket_id) { | |
56 OnSocketResume(extension_id, socket_id); | |
57 } | |
58 | |
59 void UDPSocketEventDispatcher::OnSocketResume(const std::string& extension_id, | |
60 int socket_id) { | |
61 DCHECK(BrowserThread::CurrentlyOn(thread_id_)); | |
62 | |
63 ReceiveParams params; | |
64 params.thread_id = thread_id_; | |
65 params.browser_context_id = browser_context_; | |
66 params.extension_id = extension_id; | |
67 params.sockets = sockets_; | |
68 params.socket_id = socket_id; | |
69 | |
70 StartReceive(params); | |
71 } | |
72 | |
73 /* static */ | |
74 void UDPSocketEventDispatcher::StartReceive(const ReceiveParams& params) { | |
75 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
76 | |
77 ResumableUDPSocket* socket = | |
78 params.sockets->Get(params.extension_id, params.socket_id); | |
79 if (socket == NULL) { | |
80 // This can happen if the socket is closed while our callback is active. | |
81 return; | |
82 } | |
83 DCHECK(params.extension_id == socket->owner_extension_id()) | |
84 << "Socket has wrong owner."; | |
85 | |
86 // Don't start another read if the socket has been paused. | |
87 if (socket->paused()) | |
88 return; | |
89 | |
90 int buffer_size = (socket->buffer_size() <= 0 ? 4096 : socket->buffer_size()); | |
91 socket->RecvFrom(buffer_size, | |
92 base::Bind(&UDPSocketEventDispatcher::ReceiveCallback, | |
93 params)); | |
94 } | |
95 | |
96 /* static */ | |
97 void UDPSocketEventDispatcher::ReceiveCallback( | |
98 const ReceiveParams& params, | |
99 int bytes_read, | |
100 scoped_refptr<net::IOBuffer> io_buffer, | |
101 const std::string& address, | |
102 int port) { | |
103 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
104 | |
105 // If |bytes_read| == 0, the message contained no data. | |
106 // If |bytes_read| < 0, there was a network error, and |bytes_read| is a value | |
107 // from "net::ERR_". | |
108 | |
109 if (bytes_read >= 0) { | |
110 // Dispatch "onReceive" event. | |
111 sockets_udp::ReceiveInfo receive_info; | |
112 receive_info.socket_id = params.socket_id; | |
113 receive_info.data = std::string(io_buffer->data(), bytes_read); | |
114 receive_info.remote_address = address; | |
115 receive_info.remote_port = port; | |
116 scoped_ptr<base::ListValue> args = | |
117 sockets_udp::OnReceive::Create(receive_info); | |
118 scoped_ptr<Event> event( | |
119 new Event(sockets_udp::OnReceive::kEventName, args.Pass())); | |
120 PostEvent(params, event.Pass()); | |
121 | |
122 // Post a task to delay the read until the socket is available, as | |
123 // calling StartReceive at this point would error with ERR_IO_PENDING. | |
124 BrowserThread::PostTask( | |
125 params.thread_id, FROM_HERE, | |
126 base::Bind(&UDPSocketEventDispatcher::StartReceive, params)); | |
127 } else if (bytes_read == net::ERR_IO_PENDING) { | |
128 // This happens when resuming a socket which already had an | |
129 // active "recv" callback. | |
130 } else { | |
131 // Dispatch "onReceiveError" event but don't start another read to avoid | |
132 // potential infinite reads if we have a persistent network error. | |
133 sockets_udp::ReceiveErrorInfo receive_error_info; | |
134 receive_error_info.socket_id = params.socket_id; | |
135 receive_error_info.result_code = bytes_read; | |
136 scoped_ptr<base::ListValue> args = | |
137 sockets_udp::OnReceiveError::Create(receive_error_info); | |
138 scoped_ptr<Event> event( | |
139 new Event(sockets_udp::OnReceiveError::kEventName, args.Pass())); | |
140 PostEvent(params, event.Pass()); | |
141 | |
142 // Since we got an error, the socket is now "paused" until the application | |
143 // "resumes" it. | |
144 ResumableUDPSocket* socket = | |
145 params.sockets->Get(params.extension_id, params.socket_id); | |
146 if (socket) { | |
147 socket->set_paused(true); | |
148 } | |
149 } | |
150 } | |
151 | |
152 /* static */ | |
153 void UDPSocketEventDispatcher::PostEvent(const ReceiveParams& params, | |
154 scoped_ptr<Event> event) { | |
155 DCHECK(BrowserThread::CurrentlyOn(params.thread_id)); | |
156 | |
157 BrowserThread::PostTask(BrowserThread::UI, | |
158 FROM_HERE, | |
159 base::Bind(&DispatchEvent, | |
160 params.browser_context_id, | |
161 params.extension_id, | |
162 base::Passed(event.Pass()))); | |
163 } | |
164 | |
165 /*static*/ | |
166 void UDPSocketEventDispatcher::DispatchEvent(void* browser_context_id, | |
167 const std::string& extension_id, | |
168 scoped_ptr<Event> event) { | |
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
170 | |
171 content::BrowserContext* context = | |
172 reinterpret_cast<content::BrowserContext*>(browser_context_id); | |
173 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context)) | |
174 return; | |
175 EventRouter* router = ExtensionSystem::Get(context)->event_router(); | |
176 if (router) | |
177 router->DispatchEventToExtension(extension_id, event.Pass()); | |
178 } | |
179 | |
180 } // namespace api | |
181 } // namespace extensions | |
OLD | NEW |