- add sources.
[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/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"
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.Get();
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   DCHECK(BrowserThread::CurrentlyOn(thread_id_));
58
59   ReceiveParams params;
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;
65
66   StartReceive(params);
67 }
68
69 /* static */
70 void UDPSocketEventDispatcher::StartReceive(const ReceiveParams& params) {
71   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
72
73   ResumableUDPSocket* socket =
74       params.sockets->Get(params.extension_id, params.socket_id);
75   if (socket == NULL) {
76     // This can happen if the socket is closed while our callback is active.
77     return;
78   }
79   DCHECK(params.extension_id == socket->owner_extension_id())
80     << "Socket has wrong owner.";
81
82   int buffer_size = (socket->buffer_size() <= 0 ? 4096 : socket->buffer_size());
83   socket->RecvFrom(buffer_size,
84                    base::Bind(&UDPSocketEventDispatcher::ReceiveCallback,
85                    params));
86 }
87
88 /* static */
89 void UDPSocketEventDispatcher::ReceiveCallback(
90     const ReceiveParams& params,
91     int bytes_read,
92     scoped_refptr<net::IOBuffer> io_buffer,
93     const std::string& address,
94     int port) {
95   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
96
97   // Note: if "bytes_read" < 0, there was a network error, and "bytes_read" is
98   // a value from "net::ERR_".
99
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());
112
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));
118   } else {
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());
129   }
130 }
131
132 /* static */
133 void UDPSocketEventDispatcher::PostEvent(const ReceiveParams& params,
134                                          scoped_ptr<Event> event) {
135   DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
136
137   BrowserThread::PostTask(
138       BrowserThread::UI, FROM_HERE,
139       base::Bind(&DispatchEvent,
140                   params.profile_id,
141                   params.extension_id,
142                   base::Passed(event.Pass())));
143 }
144
145 /*static*/
146 void UDPSocketEventDispatcher::DispatchEvent(void* profile_id,
147                                              const std::string& extension_id,
148                                              scoped_ptr<Event> event) {
149   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150
151   Profile* profile = reinterpret_cast<Profile*>(profile_id);
152   if (!g_browser_process->profile_manager()->IsValidProfile(profile))
153     return;
154
155   EventRouter* router = ExtensionSystem::Get(profile)->event_router();
156   if (router)
157     router->DispatchEventToExtension(extension_id, event.Pass());
158 }
159
160 }  // namespace api
161 }  // namespace extensions