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
;
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
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()));
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
78 socket
->set_buffer_size(*properties
->buffer_size
.get());
84 namespace extensions
{
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(
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());
125 void SocketsTcpCreateFunction::Work() {
126 ResumableTCPSocket
* socket
= new ResumableTCPSocket(extension_
->id());
128 sockets_tcp::SocketProperties
* properties
= params_
.get()->properties
.get();
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());
148 void SocketsTcpUpdateFunction::Work() {
149 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
151 error_
= kSocketNotFoundError
;
155 SetSocketProperties(socket
, ¶ms_
.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
);
180 error_
= kSocketNotFoundError
;
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(),
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());
205 void SocketsTcpSetKeepAliveFunction::Work() {
206 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
208 error_
= kSocketNotFoundError
;
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());
231 void SocketsTcpSetNoDelayFunction::Work() {
232 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
234 error_
= kSocketNotFoundError
;
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
);
266 error_
= kSocketNotFoundError
;
267 AsyncWorkCompleted();
271 socket
->set_hostname(params_
->peer_address
);
273 content::SocketPermissionRequest
param(SocketPermissionRequest::TCP_CONNECT
,
274 params_
->peer_address
,
276 if (!SocketsManifestData::CheckRequest(extension(), param
)) {
277 error_
= kPermissionError
;
278 AsyncWorkCompleted();
282 StartDnsLookup(params_
->peer_address
);
285 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result
) {
286 if (lookup_result
== net::OK
) {
289 OnCompleted(lookup_result
);
293 void SocketsTcpConnectFunction::StartConnect() {
294 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
296 error_
= kSocketNotFoundError
;
297 AsyncWorkCompleted();
301 socket
->Connect(resolved_address_
,
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(),
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());
328 void SocketsTcpDisconnectFunction::Work() {
329 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
331 error_
= kSocketNotFoundError
;
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());
351 void SocketsTcpSendFunction::AsyncWorkStart() {
352 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
354 error_
= kSocketNotFoundError
;
355 AsyncWorkCompleted();
359 socket
->Write(io_buffer_
,
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
);
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());
397 void SocketsTcpCloseFunction::Work() {
398 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
400 error_
= kSocketNotFoundError
;
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());
418 void SocketsTcpGetInfoFunction::Work() {
419 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
421 error_
= kSocketNotFoundError
;
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();
444 ResumableTCPSocket
* socket
= GetTcpSocket(socket_id
);
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();
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
);
474 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT
));
475 error_
= kSocketNotFoundError
;
476 AsyncWorkCompleted();
480 paused_
= socket
->paused();
481 persistent_
= socket
->persistent();
483 // Make sure it's a connected TCP client socket. Error out if it's already
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();
493 if (!socket
->IsConnected()) {
494 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT
));
495 error_
= kSocketNotConnectedError
;
496 AsyncWorkCompleted();
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(
521 url_request_context
->ssl_config_service(),
522 url_request_context
->cert_verifier(),
523 url_request_context
->transport_security_state(),
526 base::Bind(&SocketsTcpSecureFunction::TlsConnectDone
, this));
529 void SocketsTcpSecureFunction::TlsConnectDone(scoped_ptr
<TLSSocket
> socket
,
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());
539 RemoveSocket(params_
->socket_id
);
540 error_
= net::ErrorToString(result
);
543 results_
= core_api::sockets_tcp::Secure::Results::Create(result
);
544 AsyncWorkCompleted();
548 } // namespace extensions