| 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 |