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.
5 #include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/extensions/api/socket/udp_socket.h"
9 #include "chrome/browser/extensions/event_router.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "net/base/net_errors.h"
15 namespace extensions {
18 using content::BrowserThread;
20 static base::LazyInstance<ProfileKeyedAPIFactory<UDPSocketEventDispatcher> >
21 g_factory = LAZY_INSTANCE_INITIALIZER;
24 ProfileKeyedAPIFactory<UDPSocketEventDispatcher>*
25 UDPSocketEventDispatcher::GetFactoryInstance() {
26 return &g_factory.Get();
30 UDPSocketEventDispatcher* UDPSocketEventDispatcher::Get(Profile* profile) {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33 return ProfileKeyedAPIFactory<UDPSocketEventDispatcher>::GetForProfile(
37 UDPSocketEventDispatcher::UDPSocketEventDispatcher(Profile* profile)
38 : thread_id_(Socket::kThreadId),
40 ApiResourceManager<ResumableUDPSocket>* manager =
41 ApiResourceManager<ResumableUDPSocket>::Get(profile);
42 DCHECK(manager) << "There is no 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<ResumableUDPSocket>.";
46 sockets_ = manager->data_;
49 UDPSocketEventDispatcher::~UDPSocketEventDispatcher() {}
51 UDPSocketEventDispatcher::ReceiveParams::ReceiveParams() {}
53 UDPSocketEventDispatcher::ReceiveParams::~ReceiveParams() {}
55 void UDPSocketEventDispatcher::OnSocketBind(const std::string& extension_id,
57 DCHECK(BrowserThread::CurrentlyOn(thread_id_));
60 params.thread_id = thread_id_;
61 params.profile_id = profile_;
62 params.extension_id = extension_id;
63 params.sockets = sockets_;
64 params.socket_id = socket_id;
70 void UDPSocketEventDispatcher::StartReceive(const ReceiveParams& params) {
71 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
73 ResumableUDPSocket* socket =
74 params.sockets->Get(params.extension_id, params.socket_id);
76 // This can happen if the socket is closed while our callback is active.
79 DCHECK(params.extension_id == socket->owner_extension_id())
80 << "Socket has wrong owner.";
82 int buffer_size = (socket->buffer_size() <= 0 ? 4096 : socket->buffer_size());
83 socket->RecvFrom(buffer_size,
84 base::Bind(&UDPSocketEventDispatcher::ReceiveCallback,
89 void UDPSocketEventDispatcher::ReceiveCallback(
90 const ReceiveParams& params,
92 scoped_refptr<net::IOBuffer> io_buffer,
93 const std::string& address,
95 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
97 // Note: if "bytes_read" < 0, there was a network error, and "bytes_read" is
98 // a value from "net::ERR_".
100 if (bytes_read >= 0) {
101 // Dispatch "onReceive" event.
102 sockets_udp::ReceiveInfo receive_info;
103 receive_info.socket_id = params.socket_id;
104 receive_info.data = std::string(io_buffer->data(), bytes_read);
105 receive_info.remote_address = address;
106 receive_info.remote_port = port;
107 scoped_ptr<base::ListValue> args =
108 sockets_udp::OnReceive::Create(receive_info);
109 scoped_ptr<Event> event(
110 new Event(sockets_udp::OnReceive::kEventName, args.Pass()));
111 PostEvent(params, event.Pass());
113 // Post a task to delay the read until the socket is available, as
114 // calling StartReceive at this point would error with ERR_IO_PENDING.
115 BrowserThread::PostTask(
116 params.thread_id, FROM_HERE,
117 base::Bind(&UDPSocketEventDispatcher::StartReceive, params));
119 // Dispatch "onReceiveError" event but don't start another read to avoid
120 // potential infinite reads if we have a persistent network error.
121 sockets_udp::ReceiveErrorInfo receive_error_info;
122 receive_error_info.socket_id = params.socket_id;
123 receive_error_info.result_code = bytes_read;
124 scoped_ptr<base::ListValue> args =
125 sockets_udp::OnReceiveError::Create(receive_error_info);
126 scoped_ptr<Event> event(
127 new Event(sockets_udp::OnReceiveError::kEventName, args.Pass()));
128 PostEvent(params, event.Pass());
133 void UDPSocketEventDispatcher::PostEvent(const ReceiveParams& params,
134 scoped_ptr<Event> event) {
135 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
137 BrowserThread::PostTask(
138 BrowserThread::UI, FROM_HERE,
139 base::Bind(&DispatchEvent,
142 base::Passed(event.Pass())));
146 void UDPSocketEventDispatcher::DispatchEvent(void* profile_id,
147 const std::string& extension_id,
148 scoped_ptr<Event> event) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
151 Profile* profile = reinterpret_cast<Profile*>(profile_id);
152 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
155 EventRouter* router = ExtensionSystem::Get(profile)->event_router();
157 router->DispatchEventToExtension(extension_id, event.Pass());
161 } // namespace extensions