• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "extensions/browser/api/sockets_tcp/sockets_tcp_api.h"
6 
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"
12 
13 using extensions::ResumableTCPSocket;
14 using extensions::core_api::sockets_tcp::SocketInfo;
15 using extensions::core_api::sockets_tcp::SocketProperties;
16 
17 namespace {
18 
19 const char kSocketNotFoundError[] = "Socket not found";
20 const char kPermissionError[] = "Does not have permission";
21 
CreateSocketInfo(int socket_id,ResumableTCPSocket * socket)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()));
30   }
31   socket_info->persistent = socket->persistent();
32   if (socket->buffer_size() > 0) {
33     socket_info->buffer_size.reset(new int(socket->buffer_size()));
34   }
35   socket_info->paused = socket->paused();
36   socket_info->connected = socket->IsConnected();
37 
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()));
44   }
45 
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()));
55   }
56 
57   return socket_info;
58 }
59 
SetSocketProperties(ResumableTCPSocket * socket,SocketProperties * properties)60 void SetSocketProperties(ResumableTCPSocket* socket,
61                          SocketProperties* properties) {
62   if (properties->name.get()) {
63     socket->set_name(*properties->name.get());
64   }
65   if (properties->persistent.get()) {
66     socket->set_persistent(*properties->persistent.get());
67   }
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());
72   }
73 }
74 
75 }  // namespace
76 
77 namespace extensions {
78 namespace core_api {
79 
80 using content::SocketPermissionRequest;
81 
~TCPSocketAsyncApiFunction()82 TCPSocketAsyncApiFunction::~TCPSocketAsyncApiFunction() {}
83 
84 scoped_ptr<SocketResourceManagerInterface>
CreateSocketResourceManager()85 TCPSocketAsyncApiFunction::CreateSocketResourceManager() {
86   return scoped_ptr<SocketResourceManagerInterface>(
87              new SocketResourceManager<ResumableTCPSocket>()).Pass();
88 }
89 
GetTcpSocket(int socket_id)90 ResumableTCPSocket* TCPSocketAsyncApiFunction::GetTcpSocket(int socket_id) {
91   return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
92 }
93 
94 TCPSocketExtensionWithDnsLookupFunction::
~TCPSocketExtensionWithDnsLookupFunction()95     ~TCPSocketExtensionWithDnsLookupFunction() {}
96 
97 scoped_ptr<SocketResourceManagerInterface>
CreateSocketResourceManager()98 TCPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
99   return scoped_ptr<SocketResourceManagerInterface>(
100              new SocketResourceManager<ResumableTCPSocket>()).Pass();
101 }
102 
GetTcpSocket(int socket_id)103 ResumableTCPSocket* TCPSocketExtensionWithDnsLookupFunction::GetTcpSocket(
104     int socket_id) {
105   return static_cast<ResumableTCPSocket*>(GetSocket(socket_id));
106 }
107 
SocketsTcpCreateFunction()108 SocketsTcpCreateFunction::SocketsTcpCreateFunction() {}
109 
~SocketsTcpCreateFunction()110 SocketsTcpCreateFunction::~SocketsTcpCreateFunction() {}
111 
Prepare()112 bool SocketsTcpCreateFunction::Prepare() {
113   params_ = sockets_tcp::Create::Params::Create(*args_);
114   EXTENSION_FUNCTION_VALIDATE(params_.get());
115   return true;
116 }
117 
Work()118 void SocketsTcpCreateFunction::Work() {
119   ResumableTCPSocket* socket = new ResumableTCPSocket(extension_->id());
120 
121   sockets_tcp::SocketProperties* properties = params_.get()->properties.get();
122   if (properties) {
123     SetSocketProperties(socket, properties);
124   }
125 
126   sockets_tcp::CreateInfo create_info;
127   create_info.socket_id = AddSocket(socket);
128   results_ = sockets_tcp::Create::Results::Create(create_info);
129 }
130 
SocketsTcpUpdateFunction()131 SocketsTcpUpdateFunction::SocketsTcpUpdateFunction() {}
132 
~SocketsTcpUpdateFunction()133 SocketsTcpUpdateFunction::~SocketsTcpUpdateFunction() {}
134 
Prepare()135 bool SocketsTcpUpdateFunction::Prepare() {
136   params_ = sockets_tcp::Update::Params::Create(*args_);
137   EXTENSION_FUNCTION_VALIDATE(params_.get());
138   return true;
139 }
140 
Work()141 void SocketsTcpUpdateFunction::Work() {
142   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
143   if (!socket) {
144     error_ = kSocketNotFoundError;
145     return;
146   }
147 
148   SetSocketProperties(socket, &params_.get()->properties);
149   results_ = sockets_tcp::Update::Results::Create();
150 }
151 
SocketsTcpSetPausedFunction()152 SocketsTcpSetPausedFunction::SocketsTcpSetPausedFunction()
153     : socket_event_dispatcher_(NULL) {}
154 
~SocketsTcpSetPausedFunction()155 SocketsTcpSetPausedFunction::~SocketsTcpSetPausedFunction() {}
156 
Prepare()157 bool SocketsTcpSetPausedFunction::Prepare() {
158   params_ = core_api::sockets_tcp::SetPaused::Params::Create(*args_);
159   EXTENSION_FUNCTION_VALIDATE(params_.get());
160 
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;
168 }
169 
Work()170 void SocketsTcpSetPausedFunction::Work() {
171   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
172   if (!socket) {
173     error_ = kSocketNotFoundError;
174     return;
175   }
176 
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);
182     }
183   }
184 
185   results_ = sockets_tcp::SetPaused::Results::Create();
186 }
187 
SocketsTcpSetKeepAliveFunction()188 SocketsTcpSetKeepAliveFunction::SocketsTcpSetKeepAliveFunction() {}
189 
~SocketsTcpSetKeepAliveFunction()190 SocketsTcpSetKeepAliveFunction::~SocketsTcpSetKeepAliveFunction() {}
191 
Prepare()192 bool SocketsTcpSetKeepAliveFunction::Prepare() {
193   params_ = core_api::sockets_tcp::SetKeepAlive::Params::Create(*args_);
194   EXTENSION_FUNCTION_VALIDATE(params_.get());
195   return true;
196 }
197 
Work()198 void SocketsTcpSetKeepAliveFunction::Work() {
199   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
200   if (!socket) {
201     error_ = kSocketNotFoundError;
202     return;
203   }
204 
205   int delay = params_->delay ? *params_->delay.get() : 0;
206 
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);
212 }
213 
SocketsTcpSetNoDelayFunction()214 SocketsTcpSetNoDelayFunction::SocketsTcpSetNoDelayFunction() {}
215 
~SocketsTcpSetNoDelayFunction()216 SocketsTcpSetNoDelayFunction::~SocketsTcpSetNoDelayFunction() {}
217 
Prepare()218 bool SocketsTcpSetNoDelayFunction::Prepare() {
219   params_ = core_api::sockets_tcp::SetNoDelay::Params::Create(*args_);
220   EXTENSION_FUNCTION_VALIDATE(params_.get());
221   return true;
222 }
223 
Work()224 void SocketsTcpSetNoDelayFunction::Work() {
225   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
226   if (!socket) {
227     error_ = kSocketNotFoundError;
228     return;
229   }
230 
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);
236 }
237 
SocketsTcpConnectFunction()238 SocketsTcpConnectFunction::SocketsTcpConnectFunction()
239     : socket_event_dispatcher_(NULL) {}
240 
~SocketsTcpConnectFunction()241 SocketsTcpConnectFunction::~SocketsTcpConnectFunction() {}
242 
Prepare()243 bool SocketsTcpConnectFunction::Prepare() {
244   params_ = sockets_tcp::Connect::Params::Create(*args_);
245   EXTENSION_FUNCTION_VALIDATE(params_.get());
246 
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;
254 }
255 
AsyncWorkStart()256 void SocketsTcpConnectFunction::AsyncWorkStart() {
257   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
258   if (!socket) {
259     error_ = kSocketNotFoundError;
260     AsyncWorkCompleted();
261     return;
262   }
263 
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;
271   }
272 
273   StartDnsLookup(params_->peer_address);
274 }
275 
AfterDnsLookup(int lookup_result)276 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result) {
277   if (lookup_result == net::OK) {
278     StartConnect();
279   } else {
280     OnCompleted(lookup_result);
281   }
282 }
283 
StartConnect()284 void SocketsTcpConnectFunction::StartConnect() {
285   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
286   if (!socket) {
287     error_ = kSocketNotFoundError;
288     AsyncWorkCompleted();
289     return;
290   }
291 
292   socket->Connect(resolved_address_,
293                   params_->peer_port,
294                   base::Bind(&SocketsTcpConnectFunction::OnCompleted, this));
295 }
296 
OnCompleted(int net_result)297 void SocketsTcpConnectFunction::OnCompleted(int net_result) {
298   if (net_result == net::OK) {
299     socket_event_dispatcher_->OnSocketConnect(extension_->id(),
300                                               params_->socket_id);
301   }
302 
303   if (net_result != net::OK)
304     error_ = net::ErrorToString(net_result);
305   results_ = sockets_tcp::Connect::Results::Create(net_result);
306   AsyncWorkCompleted();
307 }
308 
SocketsTcpDisconnectFunction()309 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {}
310 
~SocketsTcpDisconnectFunction()311 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {}
312 
Prepare()313 bool SocketsTcpDisconnectFunction::Prepare() {
314   params_ = sockets_tcp::Disconnect::Params::Create(*args_);
315   EXTENSION_FUNCTION_VALIDATE(params_.get());
316   return true;
317 }
318 
Work()319 void SocketsTcpDisconnectFunction::Work() {
320   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
321   if (!socket) {
322     error_ = kSocketNotFoundError;
323     return;
324   }
325 
326   socket->Disconnect();
327   results_ = sockets_tcp::Disconnect::Results::Create();
328 }
329 
SocketsTcpSendFunction()330 SocketsTcpSendFunction::SocketsTcpSendFunction() : io_buffer_size_(0) {}
331 
~SocketsTcpSendFunction()332 SocketsTcpSendFunction::~SocketsTcpSendFunction() {}
333 
Prepare()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;
340 }
341 
AsyncWorkStart()342 void SocketsTcpSendFunction::AsyncWorkStart() {
343   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
344   if (!socket) {
345     error_ = kSocketNotFoundError;
346     AsyncWorkCompleted();
347     return;
348   }
349 
350   socket->Write(io_buffer_,
351                 io_buffer_size_,
352                 base::Bind(&SocketsTcpSendFunction::OnCompleted, this));
353 }
354 
OnCompleted(int net_result)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);
360   }
361 }
362 
SetSendResult(int net_result,int bytes_sent)363 void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) {
364   CHECK(net_result <= net::OK) << "Network status code must be <= net::OK";
365 
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));
370   }
371 
372   if (net_result != net::OK)
373     error_ = net::ErrorToString(net_result);
374   results_ = sockets_tcp::Send::Results::Create(send_info);
375   AsyncWorkCompleted();
376 }
377 
SocketsTcpCloseFunction()378 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {}
379 
~SocketsTcpCloseFunction()380 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {}
381 
Prepare()382 bool SocketsTcpCloseFunction::Prepare() {
383   params_ = sockets_tcp::Close::Params::Create(*args_);
384   EXTENSION_FUNCTION_VALIDATE(params_.get());
385   return true;
386 }
387 
Work()388 void SocketsTcpCloseFunction::Work() {
389   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
390   if (!socket) {
391     error_ = kSocketNotFoundError;
392     return;
393   }
394 
395   RemoveSocket(params_->socket_id);
396   results_ = sockets_tcp::Close::Results::Create();
397 }
398 
SocketsTcpGetInfoFunction()399 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {}
400 
~SocketsTcpGetInfoFunction()401 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {}
402 
Prepare()403 bool SocketsTcpGetInfoFunction::Prepare() {
404   params_ = sockets_tcp::GetInfo::Params::Create(*args_);
405   EXTENSION_FUNCTION_VALIDATE(params_.get());
406   return true;
407 }
408 
Work()409 void SocketsTcpGetInfoFunction::Work() {
410   ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id);
411   if (!socket) {
412     error_ = kSocketNotFoundError;
413     return;
414   }
415 
416   linked_ptr<sockets_tcp::SocketInfo> socket_info =
417       CreateSocketInfo(params_->socket_id, socket);
418   results_ = sockets_tcp::GetInfo::Results::Create(*socket_info);
419 }
420 
SocketsTcpGetSocketsFunction()421 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {}
422 
~SocketsTcpGetSocketsFunction()423 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {}
424 
Prepare()425 bool SocketsTcpGetSocketsFunction::Prepare() { return true; }
426 
Work()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));
438       }
439     }
440   }
441   results_ = sockets_tcp::GetSockets::Results::Create(socket_infos);
442 }
443 
444 }  // namespace core_api
445 }  // namespace extensions
446