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
;
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
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()));
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
71 socket
->set_buffer_size(*properties
->buffer_size
.get());
77 namespace extensions
{
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(
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());
118 void SocketsTcpCreateFunction::Work() {
119 ResumableTCPSocket
* socket
= new ResumableTCPSocket(extension_
->id());
121 sockets_tcp::SocketProperties
* properties
= params_
.get()->properties
.get();
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());
141 void SocketsTcpUpdateFunction::Work() {
142 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
144 error_
= kSocketNotFoundError
;
148 SetSocketProperties(socket
, ¶ms_
.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
);
173 error_
= kSocketNotFoundError
;
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(),
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());
198 void SocketsTcpSetKeepAliveFunction::Work() {
199 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
201 error_
= kSocketNotFoundError
;
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());
224 void SocketsTcpSetNoDelayFunction::Work() {
225 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
227 error_
= kSocketNotFoundError
;
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
);
259 error_
= kSocketNotFoundError
;
260 AsyncWorkCompleted();
264 content::SocketPermissionRequest
param(SocketPermissionRequest::TCP_CONNECT
,
265 params_
->peer_address
,
267 if (!SocketsManifestData::CheckRequest(GetExtension(), param
)) {
268 error_
= kPermissionError
;
269 AsyncWorkCompleted();
273 StartDnsLookup(params_
->peer_address
);
276 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result
) {
277 if (lookup_result
== net::OK
) {
280 OnCompleted(lookup_result
);
284 void SocketsTcpConnectFunction::StartConnect() {
285 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
287 error_
= kSocketNotFoundError
;
288 AsyncWorkCompleted();
292 socket
->Connect(resolved_address_
,
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(),
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());
319 void SocketsTcpDisconnectFunction::Work() {
320 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
322 error_
= kSocketNotFoundError
;
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());
342 void SocketsTcpSendFunction::AsyncWorkStart() {
343 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
345 error_
= kSocketNotFoundError
;
346 AsyncWorkCompleted();
350 socket
->Write(io_buffer_
,
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
);
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());
388 void SocketsTcpCloseFunction::Work() {
389 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
391 error_
= kSocketNotFoundError
;
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());
409 void SocketsTcpGetInfoFunction::Work() {
410 ResumableTCPSocket
* socket
= GetTcpSocket(params_
->socket_id
);
412 error_
= kSocketNotFoundError
;
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();
435 ResumableTCPSocket
* socket
= GetTcpSocket(socket_id
);
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