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