Update path of checkdeps to buildtools checkout
[chromium-blink-merge.git] / extensions / browser / api / sockets_tcp / sockets_tcp_api.cc
blob073a5f42bea88a95f557df4ff2b58685f78e9a91
1 // Copyright 2014 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 "extensions/browser/api/sockets_tcp/sockets_tcp_api.h"
7 #include "content/public/common/socket_permission_request.h"
8 #include "extensions/browser/api/socket/tcp_socket.h"
9 #include "extensions/browser/api/sockets_tcp/tcp_socket_event_dispatcher.h"
10 #include "extensions/common/api/sockets/sockets_manifest_data.h"
11 #include "net/base/net_errors.h"
13 using extensions::ResumableTCPSocket;
14 using extensions::core_api::sockets_tcp::SocketInfo;
15 using extensions::core_api::sockets_tcp::SocketProperties;
17 namespace {
19 const char kSocketNotFoundError[] = "Socket not found";
20 const char kPermissionError[] = "Does not have permission";
22 linked_ptr<SocketInfo> CreateSocketInfo(int socket_id,
23 ResumableTCPSocket* socket) {
24 linked_ptr<SocketInfo> socket_info(new SocketInfo());
25 // This represents what we know about the socket, and does not call through
26 // to the system.
27 socket_info->socket_id = socket_id;
28 if (!socket->name().empty()) {
29 socket_info->name.reset(new std::string(socket->name()));
31 socket_info->persistent = socket->persistent();
32 if (socket->buffer_size() > 0) {
33 socket_info->buffer_size.reset(new int(socket->buffer_size()));
35 socket_info->paused = socket->paused();
36 socket_info->connected = socket->IsConnected();
38 // Grab the local address as known by the OS.
39 net::IPEndPoint localAddress;
40 if (socket->GetLocalAddress(&localAddress)) {
41 socket_info->local_address.reset(
42 new std::string(localAddress.ToStringWithoutPort()));
43 socket_info->local_port.reset(new int(localAddress.port()));
46 // Grab the peer address as known by the OS. This and the call below will
47 // always succeed while the socket is connected, even if the socket has
48 // been remotely closed by the peer; only reading the socket will reveal
49 // that it should be closed locally.
50 net::IPEndPoint peerAddress;
51 if (socket->GetPeerAddress(&peerAddress)) {
52 socket_info->peer_address.reset(
53 new std::string(peerAddress.ToStringWithoutPort()));
54 socket_info->peer_port.reset(new int(peerAddress.port()));
57 return socket_info;
60 void SetSocketProperties(ResumableTCPSocket* socket,
61 SocketProperties* properties) {
62 if (properties->name.get()) {
63 socket->set_name(*properties->name.get());
65 if (properties->persistent.get()) {
66 socket->set_persistent(*properties->persistent.get());
68 if (properties->buffer_size.get()) {
69 // buffer size is validated when issuing the actual Recv operation
70 // on the socket.
71 socket->set_buffer_size(*properties->buffer_size.get());
75 } // namespace
77 namespace extensions {
78 namespace core_api {
80 using content::SocketPermissionRequest;
82 TCPSocketAsyncApiFunction::~TCPSocketAsyncApiFunction() {}
84 scoped_ptr<SocketResourceManagerInterface>
85 TCPSocketAsyncApiFunction::CreateSocketResourceManager() {
86 return scoped_ptr<SocketResourceManagerInterface>(
87 new SocketResourceManager<ResumableTCPSocket>()).Pass();
90 ResumableTCPSocket* TCPSocketAsyncApiFunction::GetTcpSocket(int socket_id) {
91 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
94 TCPSocketExtensionWithDnsLookupFunction::
95 ~TCPSocketExtensionWithDnsLookupFunction() {}
97 scoped_ptr<SocketResourceManagerInterface>
98 TCPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
99 return scoped_ptr<SocketResourceManagerInterface>(
100 new SocketResourceManager<ResumableTCPSocket>()).Pass();
103 ResumableTCPSocket* TCPSocketExtensionWithDnsLookupFunction::GetTcpSocket(
104 int socket_id) {
105 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
108 SocketsTcpCreateFunction::SocketsTcpCreateFunction() {}
110 SocketsTcpCreateFunction::~SocketsTcpCreateFunction() {}
112 bool SocketsTcpCreateFunction::Prepare() {
113 params_ = sockets_tcp::Create::Params::Create(*args_);
114 EXTENSION_FUNCTION_VALIDATE(params_.get());
115 return true;
118 void SocketsTcpCreateFunction::Work() {
119 ResumableTCPSocket* socket = new ResumableTCPSocket(extension_->id());
121 sockets_tcp::SocketProperties* properties = params_.get()->properties.get();
122 if (properties) {
123 SetSocketProperties(socket, properties);
126 sockets_tcp::CreateInfo create_info;
127 create_info.socket_id = AddSocket(socket);
128 results_ = sockets_tcp::Create::Results::Create(create_info);
131 SocketsTcpUpdateFunction::SocketsTcpUpdateFunction() {}
133 SocketsTcpUpdateFunction::~SocketsTcpUpdateFunction() {}
135 bool SocketsTcpUpdateFunction::Prepare() {
136 params_ = sockets_tcp::Update::Params::Create(*args_);
137 EXTENSION_FUNCTION_VALIDATE(params_.get());
138 return true;
141 void SocketsTcpUpdateFunction::Work() {
142 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
143 if (!socket) {
144 error_ = kSocketNotFoundError;
145 return;
148 SetSocketProperties(socket, &params_.get()->properties);
149 results_ = sockets_tcp::Update::Results::Create();
152 SocketsTcpSetPausedFunction::SocketsTcpSetPausedFunction()
153 : socket_event_dispatcher_(NULL) {}
155 SocketsTcpSetPausedFunction::~SocketsTcpSetPausedFunction() {}
157 bool SocketsTcpSetPausedFunction::Prepare() {
158 params_ = core_api::sockets_tcp::SetPaused::Params::Create(*args_);
159 EXTENSION_FUNCTION_VALIDATE(params_.get());
161 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
162 DCHECK(socket_event_dispatcher_)
163 << "There is no socket event dispatcher. "
164 "If this assertion is failing during a test, then it is likely that "
165 "TestExtensionSystem is failing to provide an instance of "
166 "TCPSocketEventDispatcher.";
167 return socket_event_dispatcher_ != NULL;
170 void SocketsTcpSetPausedFunction::Work() {
171 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
172 if (!socket) {
173 error_ = kSocketNotFoundError;
174 return;
177 if (socket->paused() != params_->paused) {
178 socket->set_paused(params_->paused);
179 if (socket->IsConnected() && !params_->paused) {
180 socket_event_dispatcher_->OnSocketResume(extension_->id(),
181 params_->socket_id);
185 results_ = sockets_tcp::SetPaused::Results::Create();
188 SocketsTcpSetKeepAliveFunction::SocketsTcpSetKeepAliveFunction() {}
190 SocketsTcpSetKeepAliveFunction::~SocketsTcpSetKeepAliveFunction() {}
192 bool SocketsTcpSetKeepAliveFunction::Prepare() {
193 params_ = core_api::sockets_tcp::SetKeepAlive::Params::Create(*args_);
194 EXTENSION_FUNCTION_VALIDATE(params_.get());
195 return true;
198 void SocketsTcpSetKeepAliveFunction::Work() {
199 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
200 if (!socket) {
201 error_ = kSocketNotFoundError;
202 return;
205 int delay = params_->delay ? *params_->delay.get() : 0;
207 bool success = socket->SetKeepAlive(params_->enable, delay);
208 int net_result = (success ? net::OK : net::ERR_FAILED);
209 if (net_result != net::OK)
210 error_ = net::ErrorToString(net_result);
211 results_ = sockets_tcp::SetKeepAlive::Results::Create(net_result);
214 SocketsTcpSetNoDelayFunction::SocketsTcpSetNoDelayFunction() {}
216 SocketsTcpSetNoDelayFunction::~SocketsTcpSetNoDelayFunction() {}
218 bool SocketsTcpSetNoDelayFunction::Prepare() {
219 params_ = core_api::sockets_tcp::SetNoDelay::Params::Create(*args_);
220 EXTENSION_FUNCTION_VALIDATE(params_.get());
221 return true;
224 void SocketsTcpSetNoDelayFunction::Work() {
225 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
226 if (!socket) {
227 error_ = kSocketNotFoundError;
228 return;
231 bool success = socket->SetNoDelay(params_->no_delay);
232 int net_result = (success ? net::OK : net::ERR_FAILED);
233 if (net_result != net::OK)
234 error_ = net::ErrorToString(net_result);
235 results_ = sockets_tcp::SetNoDelay::Results::Create(net_result);
238 SocketsTcpConnectFunction::SocketsTcpConnectFunction()
239 : socket_event_dispatcher_(NULL) {}
241 SocketsTcpConnectFunction::~SocketsTcpConnectFunction() {}
243 bool SocketsTcpConnectFunction::Prepare() {
244 params_ = sockets_tcp::Connect::Params::Create(*args_);
245 EXTENSION_FUNCTION_VALIDATE(params_.get());
247 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
248 DCHECK(socket_event_dispatcher_)
249 << "There is no socket event dispatcher. "
250 "If this assertion is failing during a test, then it is likely that "
251 "TestExtensionSystem is failing to provide an instance of "
252 "TCPSocketEventDispatcher.";
253 return socket_event_dispatcher_ != NULL;
256 void SocketsTcpConnectFunction::AsyncWorkStart() {
257 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
258 if (!socket) {
259 error_ = kSocketNotFoundError;
260 AsyncWorkCompleted();
261 return;
264 content::SocketPermissionRequest param(SocketPermissionRequest::TCP_CONNECT,
265 params_->peer_address,
266 params_->peer_port);
267 if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
268 error_ = kPermissionError;
269 AsyncWorkCompleted();
270 return;
273 StartDnsLookup(params_->peer_address);
276 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result) {
277 if (lookup_result == net::OK) {
278 StartConnect();
279 } else {
280 OnCompleted(lookup_result);
284 void SocketsTcpConnectFunction::StartConnect() {
285 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
286 if (!socket) {
287 error_ = kSocketNotFoundError;
288 AsyncWorkCompleted();
289 return;
292 socket->Connect(resolved_address_,
293 params_->peer_port,
294 base::Bind(&SocketsTcpConnectFunction::OnCompleted, this));
297 void SocketsTcpConnectFunction::OnCompleted(int net_result) {
298 if (net_result == net::OK) {
299 socket_event_dispatcher_->OnSocketConnect(extension_->id(),
300 params_->socket_id);
303 if (net_result != net::OK)
304 error_ = net::ErrorToString(net_result);
305 results_ = sockets_tcp::Connect::Results::Create(net_result);
306 AsyncWorkCompleted();
309 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {}
311 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {}
313 bool SocketsTcpDisconnectFunction::Prepare() {
314 params_ = sockets_tcp::Disconnect::Params::Create(*args_);
315 EXTENSION_FUNCTION_VALIDATE(params_.get());
316 return true;
319 void SocketsTcpDisconnectFunction::Work() {
320 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
321 if (!socket) {
322 error_ = kSocketNotFoundError;
323 return;
326 socket->Disconnect();
327 results_ = sockets_tcp::Disconnect::Results::Create();
330 SocketsTcpSendFunction::SocketsTcpSendFunction() : io_buffer_size_(0) {}
332 SocketsTcpSendFunction::~SocketsTcpSendFunction() {}
334 bool SocketsTcpSendFunction::Prepare() {
335 params_ = sockets_tcp::Send::Params::Create(*args_);
336 EXTENSION_FUNCTION_VALIDATE(params_.get());
337 io_buffer_size_ = params_->data.size();
338 io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
339 return true;
342 void SocketsTcpSendFunction::AsyncWorkStart() {
343 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
344 if (!socket) {
345 error_ = kSocketNotFoundError;
346 AsyncWorkCompleted();
347 return;
350 socket->Write(io_buffer_,
351 io_buffer_size_,
352 base::Bind(&SocketsTcpSendFunction::OnCompleted, this));
355 void SocketsTcpSendFunction::OnCompleted(int net_result) {
356 if (net_result >= net::OK) {
357 SetSendResult(net::OK, net_result);
358 } else {
359 SetSendResult(net_result, -1);
363 void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) {
364 CHECK(net_result <= net::OK) << "Network status code must be <= net::OK";
366 sockets_tcp::SendInfo send_info;
367 send_info.result_code = net_result;
368 if (net_result == net::OK) {
369 send_info.bytes_sent.reset(new int(bytes_sent));
372 if (net_result != net::OK)
373 error_ = net::ErrorToString(net_result);
374 results_ = sockets_tcp::Send::Results::Create(send_info);
375 AsyncWorkCompleted();
378 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {}
380 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {}
382 bool SocketsTcpCloseFunction::Prepare() {
383 params_ = sockets_tcp::Close::Params::Create(*args_);
384 EXTENSION_FUNCTION_VALIDATE(params_.get());
385 return true;
388 void SocketsTcpCloseFunction::Work() {
389 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
390 if (!socket) {
391 error_ = kSocketNotFoundError;
392 return;
395 RemoveSocket(params_->socket_id);
396 results_ = sockets_tcp::Close::Results::Create();
399 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {}
401 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {}
403 bool SocketsTcpGetInfoFunction::Prepare() {
404 params_ = sockets_tcp::GetInfo::Params::Create(*args_);
405 EXTENSION_FUNCTION_VALIDATE(params_.get());
406 return true;
409 void SocketsTcpGetInfoFunction::Work() {
410 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
411 if (!socket) {
412 error_ = kSocketNotFoundError;
413 return;
416 linked_ptr<sockets_tcp::SocketInfo> socket_info =
417 CreateSocketInfo(params_->socket_id, socket);
418 results_ = sockets_tcp::GetInfo::Results::Create(*socket_info);
421 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {}
423 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {}
425 bool SocketsTcpGetSocketsFunction::Prepare() { return true; }
427 void SocketsTcpGetSocketsFunction::Work() {
428 std::vector<linked_ptr<sockets_tcp::SocketInfo> > socket_infos;
429 base::hash_set<int>* resource_ids = GetSocketIds();
430 if (resource_ids != NULL) {
431 for (base::hash_set<int>::iterator it = resource_ids->begin();
432 it != resource_ids->end();
433 ++it) {
434 int socket_id = *it;
435 ResumableTCPSocket* socket = GetTcpSocket(socket_id);
436 if (socket) {
437 socket_infos.push_back(CreateSocketInfo(socket_id, socket));
441 results_ = sockets_tcp::GetSockets::Results::Create(socket_infos);
444 } // namespace core_api
445 } // namespace extensions