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, ¶ms_.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