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::api::sockets_tcp::SocketInfo
;
19 using extensions::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_
= 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_
= 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_
= 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(net::HostPortPair(params_
->peer_address
, params_
->peer_port
));
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(addresses_
,
302 base::Bind(&SocketsTcpConnectFunction::OnCompleted
, this));
305 void SocketsTcpConnectFunction::OnCompleted(int net_result
) {
306 if (net_result
== net::OK
) {
307 socket_event_dispatcher_
->OnSocketConnect(extension_
->id(),
311 if (net_result
!= net::OK
)
312 error_
= net::ErrorToString(net_result
);
313 results_
= sockets_tcp::Connect::Results::Create(net_result
);
314 AsyncWorkCompleted();
317 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {}
319 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {}
321 bool SocketsTcpDisconnectFunction::Prepare() {
322 params_
= sockets_tcp::Disconnect::Params::Create(*args_
);
323 EXTENSION_FUNCTION_VALIDATE(params_
.get());
327 void SocketsTcpDisconnectFunction::Work() {
328 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
330 error_
= kSocketNotFoundError
;
334 socket
->Disconnect();
335 results_
= sockets_tcp::Disconnect::Results::Create();
338 SocketsTcpSendFunction::SocketsTcpSendFunction() : io_buffer_size_(0) {}
340 SocketsTcpSendFunction::~SocketsTcpSendFunction() {}
342 bool SocketsTcpSendFunction::Prepare() {
343 params_
= sockets_tcp::Send::Params::Create(*args_
);
344 EXTENSION_FUNCTION_VALIDATE(params_
.get());
345 io_buffer_size_
= params_
->data
.size();
346 io_buffer_
= new net::WrappedIOBuffer(params_
->data
.data());
350 void SocketsTcpSendFunction::AsyncWorkStart() {
351 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
353 error_
= kSocketNotFoundError
;
354 AsyncWorkCompleted();
358 socket
->Write(io_buffer_
,
360 base::Bind(&SocketsTcpSendFunction::OnCompleted
, this));
363 void SocketsTcpSendFunction::OnCompleted(int net_result
) {
364 if (net_result
>= net::OK
) {
365 SetSendResult(net::OK
, net_result
);
367 SetSendResult(net_result
, -1);
371 void SocketsTcpSendFunction::SetSendResult(int net_result
, int bytes_sent
) {
372 CHECK(net_result
<= net::OK
) << "Network status code must be <= net::OK";
374 sockets_tcp::SendInfo send_info
;
375 send_info
.result_code
= net_result
;
376 if (net_result
== net::OK
) {
377 send_info
.bytes_sent
.reset(new int(bytes_sent
));
380 if (net_result
!= net::OK
)
381 error_
= net::ErrorToString(net_result
);
382 results_
= sockets_tcp::Send::Results::Create(send_info
);
383 AsyncWorkCompleted();
386 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {}
388 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {}
390 bool SocketsTcpCloseFunction::Prepare() {
391 params_
= sockets_tcp::Close::Params::Create(*args_
);
392 EXTENSION_FUNCTION_VALIDATE(params_
.get());
396 void SocketsTcpCloseFunction::Work() {
397 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
399 error_
= kSocketNotFoundError
;
403 RemoveSocket(params_
->socket_id
);
404 results_
= sockets_tcp::Close::Results::Create();
407 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {}
409 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {}
411 bool SocketsTcpGetInfoFunction::Prepare() {
412 params_
= sockets_tcp::GetInfo::Params::Create(*args_
);
413 EXTENSION_FUNCTION_VALIDATE(params_
.get());
417 void SocketsTcpGetInfoFunction::Work() {
418 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
420 error_
= kSocketNotFoundError
;
424 linked_ptr
<sockets_tcp::SocketInfo
> socket_info
=
425 CreateSocketInfo(params_
->socket_id
, socket
);
426 results_
= sockets_tcp::GetInfo::Results::Create(*socket_info
);
429 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {}
431 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {}
433 bool SocketsTcpGetSocketsFunction::Prepare() { return true; }
435 void SocketsTcpGetSocketsFunction::Work() {
436 std::vector
<linked_ptr
<sockets_tcp::SocketInfo
> > socket_infos
;
437 base::hash_set
<int>* resource_ids
= GetSocketIds();
438 if (resource_ids
!= NULL
) {
439 for (base::hash_set
<int>::iterator it
= resource_ids
->begin();
440 it
!= resource_ids
->end();
443 ResumableTCPSocket
* socket
= GetTcpSocket(socket_id
);
445 socket_infos
.push_back(CreateSocketInfo(socket_id
, socket
));
449 results_
= sockets_tcp::GetSockets::Results::Create(socket_infos
);
452 SocketsTcpSecureFunction::SocketsTcpSecureFunction() {
455 SocketsTcpSecureFunction::~SocketsTcpSecureFunction() {
458 bool SocketsTcpSecureFunction::Prepare() {
459 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
460 params_
= api::sockets_tcp::Secure::Params::Create(*args_
);
461 EXTENSION_FUNCTION_VALIDATE(params_
.get());
462 url_request_getter_
= browser_context()->GetRequestContext();
466 // Override the regular implementation, which would call AsyncWorkCompleted
467 // immediately after Work().
468 void SocketsTcpSecureFunction::AsyncWorkStart() {
469 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
471 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
473 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT
));
474 error_
= kSocketNotFoundError
;
475 AsyncWorkCompleted();
479 paused_
= socket
->paused();
480 persistent_
= socket
->persistent();
482 // Make sure it's a connected TCP client socket. Error out if it's already
484 if (socket
->GetSocketType() != Socket::TYPE_TCP
||
485 socket
->ClientStream() == NULL
) {
486 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT
));
487 error_
= kInvalidSocketStateError
;
488 AsyncWorkCompleted();
492 if (!socket
->IsConnected()) {
493 SetResult(new base::FundamentalValue(net::ERR_INVALID_ARGUMENT
));
494 error_
= kSocketNotConnectedError
;
495 AsyncWorkCompleted();
499 net::URLRequestContext
* url_request_context
=
500 url_request_getter_
->GetURLRequestContext();
502 // UpgradeSocketToTLS() uses the older API's SecureOptions. Copy over the
503 // only values inside -- TLSVersionConstraints's |min| and |max|,
504 api::socket::SecureOptions legacy_params
;
505 if (params_
->options
.get() && params_
->options
->tls_version
.get()) {
506 legacy_params
.tls_version
.reset(new api::socket::TLSVersionConstraints
);
507 if (params_
->options
->tls_version
->min
.get()) {
508 legacy_params
.tls_version
->min
.reset(
509 new std::string(*params_
->options
->tls_version
->min
.get()));
511 if (params_
->options
->tls_version
->max
.get()) {
512 legacy_params
.tls_version
->max
.reset(
513 new std::string(*params_
->options
->tls_version
->max
.get()));
517 TLSSocket::UpgradeSocketToTLS(
519 url_request_context
->ssl_config_service(),
520 url_request_context
->cert_verifier(),
521 url_request_context
->transport_security_state(),
524 base::Bind(&SocketsTcpSecureFunction::TlsConnectDone
, this));
527 void SocketsTcpSecureFunction::TlsConnectDone(scoped_ptr
<TLSSocket
> socket
,
529 // If an error occurred, socket MUST be NULL
530 DCHECK(result
== net::OK
|| socket
== NULL
);
532 if (socket
&& result
== net::OK
) {
533 socket
->set_persistent(persistent_
);
534 socket
->set_paused(paused_
);
535 ReplaceSocket(params_
->socket_id
, socket
.release());
537 RemoveSocket(params_
->socket_id
);
538 error_
= net::ErrorToString(result
);
541 results_
= api::sockets_tcp::Secure::Results::Create(result
);
542 AsyncWorkCompleted();
546 } // namespace extensions