Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / sockets_tcp / sockets_tcp_api.cc
blob6a7204c1dd9b4ff97e778d4e3632bc164e4ba0dc
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/browser/browser_context.h"
8 #include "content/public/common/socket_permission_request.h"
9 #include "extensions/browser/api/socket/tcp_socket.h"
10 #include "extensions/browser/api/socket/tls_socket.h"
11 #include "extensions/browser/api/sockets_tcp/tcp_socket_event_dispatcher.h"
12 #include "extensions/common/api/sockets/sockets_manifest_data.h"
13 #include "net/base/net_errors.h"
14 #include "net/url_request/url_request_context.h"
15 #include "net/url_request/url_request_context_getter.h"
17 using extensions::ResumableTCPSocket;
18 using extensions::core_api::sockets_tcp::SocketInfo;
19 using extensions::core_api::sockets_tcp::SocketProperties;
21 namespace {
23 const char kSocketNotFoundError[] = "Socket not found";
24 const char kPermissionError[] = "Does not have permission";
25 const char kInvalidSocketStateError[] =
26 "Socket must be a connected client TCP socket.";
27 const char kSocketNotConnectedError[] = "Socket not connected";
29 linked_ptr<SocketInfo> CreateSocketInfo(int socket_id,
30 ResumableTCPSocket* socket) {
31 linked_ptr<SocketInfo> socket_info(new SocketInfo());
32 // This represents what we know about the socket, and does not call through
33 // to the system.
34 socket_info->socket_id = socket_id;
35 if (!socket->name().empty()) {
36 socket_info->name.reset(new std::string(socket->name()));
38 socket_info->persistent = socket->persistent();
39 if (socket->buffer_size() > 0) {
40 socket_info->buffer_size.reset(new int(socket->buffer_size()));
42 socket_info->paused = socket->paused();
43 socket_info->connected = socket->IsConnected();
45 // Grab the local address as known by the OS.
46 net::IPEndPoint localAddress;
47 if (socket->GetLocalAddress(&localAddress)) {
48 socket_info->local_address.reset(
49 new std::string(localAddress.ToStringWithoutPort()));
50 socket_info->local_port.reset(new int(localAddress.port()));
53 // Grab the peer address as known by the OS. This and the call below will
54 // always succeed while the socket is connected, even if the socket has
55 // been remotely closed by the peer; only reading the socket will reveal
56 // that it should be closed locally.
57 net::IPEndPoint peerAddress;
58 if (socket->GetPeerAddress(&peerAddress)) {
59 socket_info->peer_address.reset(
60 new std::string(peerAddress.ToStringWithoutPort()));
61 socket_info->peer_port.reset(new int(peerAddress.port()));
64 return socket_info;
67 void SetSocketProperties(ResumableTCPSocket* socket,
68 SocketProperties* properties) {
69 if (properties->name.get()) {
70 socket->set_name(*properties->name.get());
72 if (properties->persistent.get()) {
73 socket->set_persistent(*properties->persistent.get());
75 if (properties->buffer_size.get()) {
76 // buffer size is validated when issuing the actual Recv operation
77 // on the socket.
78 socket->set_buffer_size(*properties->buffer_size.get());
82 } // namespace
84 namespace extensions {
85 namespace core_api {
87 using content::SocketPermissionRequest;
89 TCPSocketAsyncApiFunction::~TCPSocketAsyncApiFunction() {}
91 scoped_ptr<SocketResourceManagerInterface>
92 TCPSocketAsyncApiFunction::CreateSocketResourceManager() {
93 return scoped_ptr<SocketResourceManagerInterface>(
94 new SocketResourceManager<ResumableTCPSocket>()).Pass();
97 ResumableTCPSocket* TCPSocketAsyncApiFunction::GetTcpSocket(int socket_id) {
98 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
101 TCPSocketExtensionWithDnsLookupFunction::
102 ~TCPSocketExtensionWithDnsLookupFunction() {}
104 scoped_ptr<SocketResourceManagerInterface>
105 TCPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
106 return scoped_ptr<SocketResourceManagerInterface>(
107 new SocketResourceManager<ResumableTCPSocket>()).Pass();
110 ResumableTCPSocket* TCPSocketExtensionWithDnsLookupFunction::GetTcpSocket(
111 int socket_id) {
112 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
115 SocketsTcpCreateFunction::SocketsTcpCreateFunction() {}
117 SocketsTcpCreateFunction::~SocketsTcpCreateFunction() {}
119 bool SocketsTcpCreateFunction::Prepare() {
120 params_ = sockets_tcp::Create::Params::Create(*args_);
121 EXTENSION_FUNCTION_VALIDATE(params_.get());
122 return true;
125 void SocketsTcpCreateFunction::Work() {
126 ResumableTCPSocket* socket = new ResumableTCPSocket(extension_->id());
128 sockets_tcp::SocketProperties* properties = params_.get()->properties.get();
129 if (properties) {
130 SetSocketProperties(socket, properties);
133 sockets_tcp::CreateInfo create_info;
134 create_info.socket_id = AddSocket(socket);
135 results_ = sockets_tcp::Create::Results::Create(create_info);
138 SocketsTcpUpdateFunction::SocketsTcpUpdateFunction() {}
140 SocketsTcpUpdateFunction::~SocketsTcpUpdateFunction() {}
142 bool SocketsTcpUpdateFunction::Prepare() {
143 params_ = sockets_tcp::Update::Params::Create(*args_);
144 EXTENSION_FUNCTION_VALIDATE(params_.get());
145 return true;
148 void SocketsTcpUpdateFunction::Work() {
149 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
150 if (!socket) {
151 error_ = kSocketNotFoundError;
152 return;
155 SetSocketProperties(socket, &params_.get()->properties);
156 results_ = sockets_tcp::Update::Results::Create();
159 SocketsTcpSetPausedFunction::SocketsTcpSetPausedFunction()
160 : socket_event_dispatcher_(NULL) {}
162 SocketsTcpSetPausedFunction::~SocketsTcpSetPausedFunction() {}
164 bool SocketsTcpSetPausedFunction::Prepare() {
165 params_ = core_api::sockets_tcp::SetPaused::Params::Create(*args_);
166 EXTENSION_FUNCTION_VALIDATE(params_.get());
168 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
169 DCHECK(socket_event_dispatcher_)
170 << "There is no socket event dispatcher. "
171 "If this assertion is failing during a test, then it is likely that "
172 "TestExtensionSystem is failing to provide an instance of "
173 "TCPSocketEventDispatcher.";
174 return socket_event_dispatcher_ != NULL;
177 void SocketsTcpSetPausedFunction::Work() {
178 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
179 if (!socket) {
180 error_ = kSocketNotFoundError;
181 return;
184 if (socket->paused() != params_->paused) {
185 socket->set_paused(params_->paused);
186 if (socket->IsConnected() && !params_->paused) {
187 socket_event_dispatcher_->OnSocketResume(extension_->id(),
188 params_->socket_id);
192 results_ = sockets_tcp::SetPaused::Results::Create();
195 SocketsTcpSetKeepAliveFunction::SocketsTcpSetKeepAliveFunction() {}
197 SocketsTcpSetKeepAliveFunction::~SocketsTcpSetKeepAliveFunction() {}
199 bool SocketsTcpSetKeepAliveFunction::Prepare() {
200 params_ = core_api::sockets_tcp::SetKeepAlive::Params::Create(*args_);
201 EXTENSION_FUNCTION_VALIDATE(params_.get());
202 return true;
205 void SocketsTcpSetKeepAliveFunction::Work() {
206 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
207 if (!socket) {
208 error_ = kSocketNotFoundError;
209 return;
212 int delay = params_->delay ? *params_->delay.get() : 0;
214 bool success = socket->SetKeepAlive(params_->enable, delay);
215 int net_result = (success ? net::OK : net::ERR_FAILED);
216 if (net_result != net::OK)
217 error_ = net::ErrorToString(net_result);
218 results_ = sockets_tcp::SetKeepAlive::Results::Create(net_result);
221 SocketsTcpSetNoDelayFunction::SocketsTcpSetNoDelayFunction() {}
223 SocketsTcpSetNoDelayFunction::~SocketsTcpSetNoDelayFunction() {}
225 bool SocketsTcpSetNoDelayFunction::Prepare() {
226 params_ = core_api::sockets_tcp::SetNoDelay::Params::Create(*args_);
227 EXTENSION_FUNCTION_VALIDATE(params_.get());
228 return true;
231 void SocketsTcpSetNoDelayFunction::Work() {
232 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
233 if (!socket) {
234 error_ = kSocketNotFoundError;
235 return;
238 bool success = socket->SetNoDelay(params_->no_delay);
239 int net_result = (success ? net::OK : net::ERR_FAILED);
240 if (net_result != net::OK)
241 error_ = net::ErrorToString(net_result);
242 results_ = sockets_tcp::SetNoDelay::Results::Create(net_result);
245 SocketsTcpConnectFunction::SocketsTcpConnectFunction()
246 : socket_event_dispatcher_(NULL) {}
248 SocketsTcpConnectFunction::~SocketsTcpConnectFunction() {}
250 bool SocketsTcpConnectFunction::Prepare() {
251 params_ = sockets_tcp::Connect::Params::Create(*args_);
252 EXTENSION_FUNCTION_VALIDATE(params_.get());
254 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context());
255 DCHECK(socket_event_dispatcher_)
256 << "There is no socket event dispatcher. "
257 "If this assertion is failing during a test, then it is likely that "
258 "TestExtensionSystem is failing to provide an instance of "
259 "TCPSocketEventDispatcher.";
260 return socket_event_dispatcher_ != NULL;
263 void SocketsTcpConnectFunction::AsyncWorkStart() {
264 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
265 if (!socket) {
266 error_ = kSocketNotFoundError;
267 AsyncWorkCompleted();
268 return;
271 socket->set_hostname(params_->peer_address);
273 content::SocketPermissionRequest param(SocketPermissionRequest::TCP_CONNECT,
274 params_->peer_address,
275 params_->peer_port);
276 if (!SocketsManifestData::CheckRequest(extension(), param)) {
277 error_ = kPermissionError;
278 AsyncWorkCompleted();
279 return;
282 StartDnsLookup(params_->peer_address);
285 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result) {
286 if (lookup_result == net::OK) {
287 StartConnect();
288 } else {
289 OnCompleted(lookup_result);
293 void SocketsTcpConnectFunction::StartConnect() {
294 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
295 if (!socket) {
296 error_ = kSocketNotFoundError;
297 AsyncWorkCompleted();
298 return;
301 socket->Connect(resolved_address_,
302 params_->peer_port,
303 base::Bind(&SocketsTcpConnectFunction::OnCompleted, this));
306 void SocketsTcpConnectFunction::OnCompleted(int net_result) {
307 if (net_result == net::OK) {
308 socket_event_dispatcher_->OnSocketConnect(extension_->id(),
309 params_->socket_id);
312 if (net_result != net::OK)
313 error_ = net::ErrorToString(net_result);
314 results_ = sockets_tcp::Connect::Results::Create(net_result);
315 AsyncWorkCompleted();
318 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {}
320 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {}
322 bool SocketsTcpDisconnectFunction::Prepare() {
323 params_ = sockets_tcp::Disconnect::Params::Create(*args_);
324 EXTENSION_FUNCTION_VALIDATE(params_.get());
325 return true;
328 void SocketsTcpDisconnectFunction::Work() {
329 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
330 if (!socket) {
331 error_ = kSocketNotFoundError;
332 return;
335 socket->Disconnect();
336 results_ = sockets_tcp::Disconnect::Results::Create();
339 SocketsTcpSendFunction::SocketsTcpSendFunction() : io_buffer_size_(0) {}
341 SocketsTcpSendFunction::~SocketsTcpSendFunction() {}
343 bool SocketsTcpSendFunction::Prepare() {
344 params_ = sockets_tcp::Send::Params::Create(*args_);
345 EXTENSION_FUNCTION_VALIDATE(params_.get());
346 io_buffer_size_ = params_->data.size();
347 io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
348 return true;
351 void SocketsTcpSendFunction::AsyncWorkStart() {
352 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
353 if (!socket) {
354 error_ = kSocketNotFoundError;
355 AsyncWorkCompleted();
356 return;
359 socket->Write(io_buffer_,
360 io_buffer_size_,
361 base::Bind(&SocketsTcpSendFunction::OnCompleted, this));
364 void SocketsTcpSendFunction::OnCompleted(int net_result) {
365 if (net_result >= net::OK) {
366 SetSendResult(net::OK, net_result);
367 } else {
368 SetSendResult(net_result, -1);
372 void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) {
373 CHECK(net_result <= net::OK) << "Network status code must be <= net::OK";
375 sockets_tcp::SendInfo send_info;
376 send_info.result_code = net_result;
377 if (net_result == net::OK) {
378 send_info.bytes_sent.reset(new int(bytes_sent));
381 if (net_result != net::OK)
382 error_ = net::ErrorToString(net_result);
383 results_ = sockets_tcp::Send::Results::Create(send_info);
384 AsyncWorkCompleted();
387 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {}
389 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {}
391 bool SocketsTcpCloseFunction::Prepare() {
392 params_ = sockets_tcp::Close::Params::Create(*args_);
393 EXTENSION_FUNCTION_VALIDATE(params_.get());
394 return true;
397 void SocketsTcpCloseFunction::Work() {
398 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
399 if (!socket) {
400 error_ = kSocketNotFoundError;
401 return;
404 RemoveSocket(params_->socket_id);
405 results_ = sockets_tcp::Close::Results::Create();
408 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {}
410 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {}
412 bool SocketsTcpGetInfoFunction::Prepare() {
413 params_ = sockets_tcp::GetInfo::Params::Create(*args_);
414 EXTENSION_FUNCTION_VALIDATE(params_.get());
415 return true;
418 void SocketsTcpGetInfoFunction::Work() {
419 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
420 if (!socket) {
421 error_ = kSocketNotFoundError;
422 return;
425 linked_ptr<sockets_tcp::SocketInfo> socket_info =
426 CreateSocketInfo(params_->socket_id, socket);
427 results_ = sockets_tcp::GetInfo::Results::Create(*socket_info);
430 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {}
432 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {}
434 bool SocketsTcpGetSocketsFunction::Prepare() { return true; }
436 void SocketsTcpGetSocketsFunction::Work() {
437 std::vector<linked_ptr<sockets_tcp::SocketInfo> > socket_infos;
438 base::hash_set<int>* resource_ids = GetSocketIds();
439 if (resource_ids != NULL) {
440 for (base::hash_set<int>::iterator it = resource_ids->begin();
441 it != resource_ids->end();
442 ++it) {
443 int socket_id = *it;
444 ResumableTCPSocket* socket = GetTcpSocket(socket_id);
445 if (socket) {
446 socket_infos.push_back(CreateSocketInfo(socket_id, socket));
450 results_ = sockets_tcp::GetSockets::Results::Create(socket_infos);
453 SocketsTcpSecureFunction::SocketsTcpSecureFunction() {
456 SocketsTcpSecureFunction::~SocketsTcpSecureFunction() {
459 bool SocketsTcpSecureFunction::Prepare() {
460 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
461 params_ = core_api::sockets_tcp::Secure::Params::Create(*args_);
462 EXTENSION_FUNCTION_VALIDATE(params_.get());
463 url_request_getter_ = browser_context()->GetRequestContext();
464 return true;
467 // Override the regular implementation, which would call AsyncWorkCompleted
468 // immediately after Work().
469 void SocketsTcpSecureFunction::AsyncWorkStart() {
470 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
472 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
473 if (!socket) {
474 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
475 error_ = kSocketNotFoundError;
476 AsyncWorkCompleted();
477 return;
480 paused_ = socket->paused();
481 persistent_ = socket->persistent();
483 // Make sure it's a connected TCP client socket. Error out if it's already
484 // secure()'d.
485 if (socket->GetSocketType() != Socket::TYPE_TCP ||
486 socket->ClientStream() == NULL) {
487 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
488 error_ = kInvalidSocketStateError;
489 AsyncWorkCompleted();
490 return;
493 if (!socket->IsConnected()) {
494 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT));
495 error_ = kSocketNotConnectedError;
496 AsyncWorkCompleted();
497 return;
500 net::URLRequestContext* url_request_context =
501 url_request_getter_->GetURLRequestContext();
503 // UpgradeSocketToTLS() uses the older API's SecureOptions. Copy over the
504 // only values inside -- TLSVersionConstraints's |min| and |max|,
505 core_api::socket::SecureOptions legacy_params;
506 if (params_->options.get() && params_->options->tls_version.get()) {
507 legacy_params.tls_version.reset(
508 new core_api::socket::TLSVersionConstraints);
509 if (params_->options->tls_version->min.get()) {
510 legacy_params.tls_version->min.reset(
511 new std::string(*params_->options->tls_version->min.get()));
513 if (params_->options->tls_version->max.get()) {
514 legacy_params.tls_version->max.reset(
515 new std::string(*params_->options->tls_version->max.get()));
519 TLSSocket::UpgradeSocketToTLS(
520 socket,
521 url_request_context->ssl_config_service(),
522 url_request_context->cert_verifier(),
523 url_request_context->transport_security_state(),
524 extension_id(),
525 &legacy_params,
526 base::Bind(&SocketsTcpSecureFunction::TlsConnectDone, this));
529 void SocketsTcpSecureFunction::TlsConnectDone(scoped_ptr<TLSSocket> socket,
530 int result) {
531 // If an error occurred, socket MUST be NULL
532 DCHECK(result == net::OK || socket == NULL);
534 if (socket && result == net::OK) {
535 socket->set_persistent(persistent_);
536 socket->set_paused(paused_);
537 ReplaceSocket(params_->socket_id, socket.release());
538 } else {
539 RemoveSocket(params_->socket_id);
540 error_ = net::ErrorToString(result);
543 results_ = core_api::sockets_tcp::Secure::Results::Create(result);
544 AsyncWorkCompleted();
547 } // namespace api
548 } // namespace extensions