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_udp/sockets_udp_api.h"
6
7 #include "base/bind.h"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/storage_partition.h"
10 #include "content/public/common/socket_permission_request.h"
11 #include "extensions/browser/api/socket/udp_socket.h"
12 #include "extensions/browser/api/sockets_udp/udp_socket_event_dispatcher.h"
13 #include "extensions/common/api/sockets/sockets_manifest_data.h"
14 #include "net/base/net_errors.h"
15
16 namespace extensions {
17 namespace api {
18
19 using content::SocketPermissionRequest;
20
21 const char kSocketNotFoundError[] = "Socket not found";
22 const char kPermissionError[] = "App does not have permission";
23 const char kWildcardAddress[] = "*";
24 const int kWildcardPort = 0;
25
~UDPSocketAsyncApiFunction()26 UDPSocketAsyncApiFunction::~UDPSocketAsyncApiFunction() {}
27
28 std::unique_ptr<SocketResourceManagerInterface>
CreateSocketResourceManager()29 UDPSocketAsyncApiFunction::CreateSocketResourceManager() {
30 return std::unique_ptr<SocketResourceManagerInterface>(
31 new SocketResourceManager<ResumableUDPSocket>());
32 }
33
GetUdpSocket(int socket_id)34 ResumableUDPSocket* UDPSocketAsyncApiFunction::GetUdpSocket(int socket_id) {
35 return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
36 }
37
38 UDPSocketExtensionWithDnsLookupFunction::
~UDPSocketExtensionWithDnsLookupFunction()39 ~UDPSocketExtensionWithDnsLookupFunction() {}
40
41 std::unique_ptr<SocketResourceManagerInterface>
CreateSocketResourceManager()42 UDPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
43 return std::unique_ptr<SocketResourceManagerInterface>(
44 new SocketResourceManager<ResumableUDPSocket>());
45 }
46
GetUdpSocket(int socket_id)47 ResumableUDPSocket* UDPSocketExtensionWithDnsLookupFunction::GetUdpSocket(
48 int socket_id) {
49 return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
50 }
51
CreateSocketInfo(int socket_id,ResumableUDPSocket * socket)52 sockets_udp::SocketInfo CreateSocketInfo(int socket_id,
53 ResumableUDPSocket* socket) {
54 sockets_udp::SocketInfo socket_info;
55 // This represents what we know about the socket, and does not call through
56 // to the system.
57 socket_info.socket_id = socket_id;
58 if (!socket->name().empty()) {
59 socket_info.name.reset(new std::string(socket->name()));
60 }
61 socket_info.persistent = socket->persistent();
62 if (socket->buffer_size() > 0) {
63 socket_info.buffer_size.reset(new int(socket->buffer_size()));
64 }
65 socket_info.paused = socket->paused();
66
67 // Grab the local address as known by the OS.
68 net::IPEndPoint localAddress;
69 if (socket->GetLocalAddress(&localAddress)) {
70 socket_info.local_address.reset(
71 new std::string(localAddress.ToStringWithoutPort()));
72 socket_info.local_port.reset(new int(localAddress.port()));
73 }
74
75 return socket_info;
76 }
77
SetSocketProperties(ResumableUDPSocket * socket,sockets_udp::SocketProperties * properties)78 void SetSocketProperties(ResumableUDPSocket* socket,
79 sockets_udp::SocketProperties* properties) {
80 if (properties->name.get()) {
81 socket->set_name(*properties->name);
82 }
83 if (properties->persistent.get()) {
84 socket->set_persistent(*properties->persistent);
85 }
86 if (properties->buffer_size.get()) {
87 socket->set_buffer_size(*properties->buffer_size);
88 }
89 }
90
SocketsUdpCreateFunction()91 SocketsUdpCreateFunction::SocketsUdpCreateFunction() {}
92
~SocketsUdpCreateFunction()93 SocketsUdpCreateFunction::~SocketsUdpCreateFunction() {}
94
Prepare()95 bool SocketsUdpCreateFunction::Prepare() {
96 params_ = sockets_udp::Create::Params::Create(*args_);
97 EXTENSION_FUNCTION_VALIDATE(params_.get());
98
99 mojo::PendingRemote<network::mojom::UDPSocketListener> listener_remote;
100 socket_listener_receiver_ = listener_remote.InitWithNewPipeAndPassReceiver();
101 content::BrowserContext::GetDefaultStoragePartition(browser_context())
102 ->GetNetworkContext()
103 ->CreateUDPSocket(socket_.InitWithNewPipeAndPassReceiver(),
104 std::move(listener_remote));
105 return true;
106 }
107
Work()108 void SocketsUdpCreateFunction::Work() {
109 ResumableUDPSocket* socket = new ResumableUDPSocket(
110 std::move(socket_), std::move(socket_listener_receiver_),
111 extension_->id());
112
113 sockets_udp::SocketProperties* properties = params_->properties.get();
114 if (properties) {
115 SetSocketProperties(socket, properties);
116 }
117
118 sockets_udp::CreateInfo create_info;
119 create_info.socket_id = AddSocket(socket);
120 results_ = sockets_udp::Create::Results::Create(create_info);
121 }
122
SocketsUdpUpdateFunction()123 SocketsUdpUpdateFunction::SocketsUdpUpdateFunction() {}
124
~SocketsUdpUpdateFunction()125 SocketsUdpUpdateFunction::~SocketsUdpUpdateFunction() {}
126
Prepare()127 bool SocketsUdpUpdateFunction::Prepare() {
128 params_ = sockets_udp::Update::Params::Create(*args_);
129 EXTENSION_FUNCTION_VALIDATE(params_.get());
130 return true;
131 }
132
Work()133 void SocketsUdpUpdateFunction::Work() {
134 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
135 if (!socket) {
136 error_ = kSocketNotFoundError;
137 return;
138 }
139
140 SetSocketProperties(socket, ¶ms_->properties);
141 results_ = sockets_udp::Update::Results::Create();
142 }
143
SocketsUdpSetPausedFunction()144 SocketsUdpSetPausedFunction::SocketsUdpSetPausedFunction()
145 : socket_event_dispatcher_(NULL) {}
146
~SocketsUdpSetPausedFunction()147 SocketsUdpSetPausedFunction::~SocketsUdpSetPausedFunction() {}
148
Prepare()149 bool SocketsUdpSetPausedFunction::Prepare() {
150 params_ = api::sockets_udp::SetPaused::Params::Create(*args_);
151 EXTENSION_FUNCTION_VALIDATE(params_.get());
152
153 socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context());
154 DCHECK(socket_event_dispatcher_)
155 << "There is no socket event dispatcher. "
156 "If this assertion is failing during a test, then it is likely that "
157 "TestExtensionSystem is failing to provide an instance of "
158 "UDPSocketEventDispatcher.";
159 return socket_event_dispatcher_ != NULL;
160 }
161
Work()162 void SocketsUdpSetPausedFunction::Work() {
163 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
164 if (!socket) {
165 error_ = kSocketNotFoundError;
166 return;
167 }
168
169 if (socket->paused() != params_->paused) {
170 socket->set_paused(params_->paused);
171 if (socket->IsConnected() && !params_->paused) {
172 socket_event_dispatcher_->OnSocketResume(extension_->id(),
173 params_->socket_id);
174 }
175 }
176
177 results_ = sockets_udp::SetPaused::Results::Create();
178 }
179
SocketsUdpBindFunction()180 SocketsUdpBindFunction::SocketsUdpBindFunction()
181 : socket_event_dispatcher_(NULL) {}
182
~SocketsUdpBindFunction()183 SocketsUdpBindFunction::~SocketsUdpBindFunction() {}
184
Prepare()185 bool SocketsUdpBindFunction::Prepare() {
186 params_ = sockets_udp::Bind::Params::Create(*args_);
187 EXTENSION_FUNCTION_VALIDATE(params_.get());
188
189 socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context());
190 DCHECK(socket_event_dispatcher_)
191 << "There is no socket event dispatcher. "
192 "If this assertion is failing during a test, then it is likely that "
193 "TestExtensionSystem is failing to provide an instance of "
194 "UDPSocketEventDispatcher.";
195 return socket_event_dispatcher_ != NULL;
196 }
197
AsyncWorkStart()198 void SocketsUdpBindFunction::AsyncWorkStart() {
199 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
200 if (!socket) {
201 error_ = kSocketNotFoundError;
202 AsyncWorkCompleted();
203 return;
204 }
205
206 content::SocketPermissionRequest param(
207 SocketPermissionRequest::UDP_BIND, params_->address, params_->port);
208 if (!SocketsManifestData::CheckRequest(extension(), param)) {
209 error_ = kPermissionError;
210 AsyncWorkCompleted();
211 return;
212 }
213 socket->Bind(params_->address, params_->port,
214 base::BindOnce(&SocketsUdpBindFunction::OnCompleted, this));
215 }
216
OnCompleted(int net_result)217 void SocketsUdpBindFunction::OnCompleted(int net_result) {
218 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
219 if (!socket) {
220 error_ = kSocketNotFoundError;
221 AsyncWorkCompleted();
222 return;
223 }
224 results_ = sockets_udp::Bind::Results::Create(net_result);
225 if (net_result == net::OK) {
226 socket_event_dispatcher_->OnSocketBind(extension_->id(),
227 params_->socket_id);
228 } else {
229 error_ = net::ErrorToString(net_result);
230 AsyncWorkCompleted();
231 return;
232 }
233
234 OpenFirewallHole(params_->address, params_->socket_id, socket);
235 }
236
SocketsUdpSendFunction()237 SocketsUdpSendFunction::SocketsUdpSendFunction() : io_buffer_size_(0) {}
238
~SocketsUdpSendFunction()239 SocketsUdpSendFunction::~SocketsUdpSendFunction() {}
240
Prepare()241 bool SocketsUdpSendFunction::Prepare() {
242 params_ = sockets_udp::Send::Params::Create(*args_);
243 EXTENSION_FUNCTION_VALIDATE(params_.get());
244 io_buffer_size_ = params_->data.size();
245 io_buffer_ = base::MakeRefCounted<net::WrappedIOBuffer>(
246 reinterpret_cast<const char*>(params_->data.data()));
247
248 return true;
249 }
250
AsyncWorkStart()251 void SocketsUdpSendFunction::AsyncWorkStart() {
252 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
253 if (!socket) {
254 error_ = kSocketNotFoundError;
255 AsyncWorkCompleted();
256 return;
257 }
258
259 content::SocketPermissionRequest param(
260 SocketPermissionRequest::UDP_SEND_TO, params_->address, params_->port);
261 if (!SocketsManifestData::CheckRequest(extension(), param)) {
262 error_ = kPermissionError;
263 AsyncWorkCompleted();
264 return;
265 }
266
267 StartDnsLookup(net::HostPortPair(params_->address, params_->port));
268 }
269
AfterDnsLookup(int lookup_result)270 void SocketsUdpSendFunction::AfterDnsLookup(int lookup_result) {
271 if (lookup_result == net::OK) {
272 StartSendTo();
273 } else {
274 SetSendResult(lookup_result, -1);
275 }
276 }
277
StartSendTo()278 void SocketsUdpSendFunction::StartSendTo() {
279 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
280 if (!socket) {
281 error_ = kSocketNotFoundError;
282 AsyncWorkCompleted();
283 return;
284 }
285
286 socket->SendTo(
287 io_buffer_, io_buffer_size_, addresses_.front(),
288 base::BindRepeating(&SocketsUdpSendFunction::OnCompleted, this));
289 }
290
OnCompleted(int net_result)291 void SocketsUdpSendFunction::OnCompleted(int net_result) {
292 if (net_result >= net::OK) {
293 SetSendResult(net::OK, net_result);
294 } else {
295 SetSendResult(net_result, -1);
296 }
297 }
298
SetSendResult(int net_result,int bytes_sent)299 void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_sent) {
300 CHECK(net_result <= net::OK) << "Network status code must be < 0";
301
302 sockets_udp::SendInfo send_info;
303 send_info.result_code = net_result;
304 if (net_result == net::OK) {
305 send_info.bytes_sent.reset(new int(bytes_sent));
306 }
307
308 if (net_result != net::OK)
309 error_ = net::ErrorToString(net_result);
310 results_ = sockets_udp::Send::Results::Create(send_info);
311 AsyncWorkCompleted();
312 }
313
SocketsUdpCloseFunction()314 SocketsUdpCloseFunction::SocketsUdpCloseFunction() {}
315
~SocketsUdpCloseFunction()316 SocketsUdpCloseFunction::~SocketsUdpCloseFunction() {}
317
Prepare()318 bool SocketsUdpCloseFunction::Prepare() {
319 params_ = sockets_udp::Close::Params::Create(*args_);
320 EXTENSION_FUNCTION_VALIDATE(params_.get());
321 return true;
322 }
323
Work()324 void SocketsUdpCloseFunction::Work() {
325 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
326 if (!socket) {
327 error_ = kSocketNotFoundError;
328 return;
329 }
330
331 socket->Disconnect(false /* socket_destroying */);
332 RemoveSocket(params_->socket_id);
333 results_ = sockets_udp::Close::Results::Create();
334 }
335
SocketsUdpGetInfoFunction()336 SocketsUdpGetInfoFunction::SocketsUdpGetInfoFunction() {}
337
~SocketsUdpGetInfoFunction()338 SocketsUdpGetInfoFunction::~SocketsUdpGetInfoFunction() {}
339
Prepare()340 bool SocketsUdpGetInfoFunction::Prepare() {
341 params_ = sockets_udp::GetInfo::Params::Create(*args_);
342 EXTENSION_FUNCTION_VALIDATE(params_.get());
343 return true;
344 }
345
Work()346 void SocketsUdpGetInfoFunction::Work() {
347 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
348 if (!socket) {
349 error_ = kSocketNotFoundError;
350 return;
351 }
352
353 sockets_udp::SocketInfo socket_info =
354 CreateSocketInfo(params_->socket_id, socket);
355 results_ = sockets_udp::GetInfo::Results::Create(socket_info);
356 }
357
SocketsUdpGetSocketsFunction()358 SocketsUdpGetSocketsFunction::SocketsUdpGetSocketsFunction() {}
359
~SocketsUdpGetSocketsFunction()360 SocketsUdpGetSocketsFunction::~SocketsUdpGetSocketsFunction() {}
361
Prepare()362 bool SocketsUdpGetSocketsFunction::Prepare() { return true; }
363
Work()364 void SocketsUdpGetSocketsFunction::Work() {
365 std::vector<sockets_udp::SocketInfo> socket_infos;
366 std::unordered_set<int>* resource_ids = GetSocketIds();
367 if (resource_ids != NULL) {
368 for (int socket_id : *resource_ids) {
369 ResumableUDPSocket* socket = GetUdpSocket(socket_id);
370 if (socket) {
371 socket_infos.push_back(CreateSocketInfo(socket_id, socket));
372 }
373 }
374 }
375 results_ = sockets_udp::GetSockets::Results::Create(socket_infos);
376 }
377
SocketsUdpJoinGroupFunction()378 SocketsUdpJoinGroupFunction::SocketsUdpJoinGroupFunction() {}
379
~SocketsUdpJoinGroupFunction()380 SocketsUdpJoinGroupFunction::~SocketsUdpJoinGroupFunction() {}
381
Prepare()382 bool SocketsUdpJoinGroupFunction::Prepare() {
383 params_ = sockets_udp::JoinGroup::Params::Create(*args_);
384 EXTENSION_FUNCTION_VALIDATE(params_.get());
385 return true;
386 }
387
AsyncWorkStart()388 void SocketsUdpJoinGroupFunction::AsyncWorkStart() {
389 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
390 if (!socket) {
391 error_ = kSocketNotFoundError;
392 AsyncWorkCompleted();
393 return;
394 }
395
396 content::SocketPermissionRequest param(
397 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
398 kWildcardAddress,
399 kWildcardPort);
400 if (!SocketsManifestData::CheckRequest(extension(), param)) {
401 error_ = kPermissionError;
402 AsyncWorkCompleted();
403 return;
404 }
405
406 socket->JoinGroup(
407 params_->address,
408 base::BindOnce(&SocketsUdpJoinGroupFunction::OnCompleted, this));
409 }
410
OnCompleted(int net_result)411 void SocketsUdpJoinGroupFunction::OnCompleted(int net_result) {
412 if (net_result != net::OK)
413 error_ = net::ErrorToString(net_result);
414 results_ = sockets_udp::JoinGroup::Results::Create(net_result);
415 AsyncWorkCompleted();
416 }
417
SocketsUdpLeaveGroupFunction()418 SocketsUdpLeaveGroupFunction::SocketsUdpLeaveGroupFunction() {}
419
~SocketsUdpLeaveGroupFunction()420 SocketsUdpLeaveGroupFunction::~SocketsUdpLeaveGroupFunction() {}
421
Prepare()422 bool SocketsUdpLeaveGroupFunction::Prepare() {
423 params_ = api::sockets_udp::LeaveGroup::Params::Create(*args_);
424 EXTENSION_FUNCTION_VALIDATE(params_.get());
425 return true;
426 }
427
AsyncWorkStart()428 void SocketsUdpLeaveGroupFunction::AsyncWorkStart() {
429 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
430 if (!socket) {
431 error_ = kSocketNotFoundError;
432 AsyncWorkCompleted();
433 return;
434 }
435
436 content::SocketPermissionRequest param(
437 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
438 kWildcardAddress,
439 kWildcardPort);
440 if (!SocketsManifestData::CheckRequest(extension(), param)) {
441 error_ = kPermissionError;
442 AsyncWorkCompleted();
443 return;
444 }
445 socket->LeaveGroup(
446 params_->address,
447 base::BindOnce(&SocketsUdpLeaveGroupFunction::OnCompleted, this));
448 }
449
OnCompleted(int result)450 void SocketsUdpLeaveGroupFunction::OnCompleted(int result) {
451 if (result != net::OK)
452 error_ = net::ErrorToString(result);
453 results_ = sockets_udp::LeaveGroup::Results::Create(result);
454 AsyncWorkCompleted();
455 }
456
457 SocketsUdpSetMulticastTimeToLiveFunction::
SocketsUdpSetMulticastTimeToLiveFunction()458 SocketsUdpSetMulticastTimeToLiveFunction() {}
459
460 SocketsUdpSetMulticastTimeToLiveFunction::
~SocketsUdpSetMulticastTimeToLiveFunction()461 ~SocketsUdpSetMulticastTimeToLiveFunction() {}
462
Prepare()463 bool SocketsUdpSetMulticastTimeToLiveFunction::Prepare() {
464 params_ = api::sockets_udp::SetMulticastTimeToLive::Params::Create(*args_);
465 EXTENSION_FUNCTION_VALIDATE(params_.get());
466 return true;
467 }
468
Work()469 void SocketsUdpSetMulticastTimeToLiveFunction::Work() {
470 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
471 if (!socket) {
472 error_ = kSocketNotFoundError;
473 return;
474 }
475
476 int net_result = socket->SetMulticastTimeToLive(params_->ttl);
477 if (net_result != net::OK)
478 error_ = net::ErrorToString(net_result);
479 results_ = sockets_udp::SetMulticastTimeToLive::Results::Create(net_result);
480 }
481
482 SocketsUdpSetMulticastLoopbackModeFunction::
SocketsUdpSetMulticastLoopbackModeFunction()483 SocketsUdpSetMulticastLoopbackModeFunction() {}
484
485 SocketsUdpSetMulticastLoopbackModeFunction::
~SocketsUdpSetMulticastLoopbackModeFunction()486 ~SocketsUdpSetMulticastLoopbackModeFunction() {}
487
Prepare()488 bool SocketsUdpSetMulticastLoopbackModeFunction::Prepare() {
489 params_ = api::sockets_udp::SetMulticastLoopbackMode::Params::Create(*args_);
490 EXTENSION_FUNCTION_VALIDATE(params_.get());
491 return true;
492 }
493
Work()494 void SocketsUdpSetMulticastLoopbackModeFunction::Work() {
495 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
496 if (!socket) {
497 error_ = kSocketNotFoundError;
498 return;
499 }
500
501 int net_result = socket->SetMulticastLoopbackMode(params_->enabled);
502 if (net_result != net::OK)
503 error_ = net::ErrorToString(net_result);
504 results_ = sockets_udp::SetMulticastLoopbackMode::Results::Create(net_result);
505 }
506
SocketsUdpGetJoinedGroupsFunction()507 SocketsUdpGetJoinedGroupsFunction::SocketsUdpGetJoinedGroupsFunction() {}
508
~SocketsUdpGetJoinedGroupsFunction()509 SocketsUdpGetJoinedGroupsFunction::~SocketsUdpGetJoinedGroupsFunction() {}
510
Prepare()511 bool SocketsUdpGetJoinedGroupsFunction::Prepare() {
512 params_ = api::sockets_udp::GetJoinedGroups::Params::Create(*args_);
513 EXTENSION_FUNCTION_VALIDATE(params_.get());
514 return true;
515 }
516
Work()517 void SocketsUdpGetJoinedGroupsFunction::Work() {
518 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
519 if (!socket) {
520 error_ = kSocketNotFoundError;
521 return;
522 }
523
524 content::SocketPermissionRequest param(
525 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
526 kWildcardAddress,
527 kWildcardPort);
528 if (!SocketsManifestData::CheckRequest(extension(), param)) {
529 error_ = kPermissionError;
530 return;
531 }
532
533 const std::vector<std::string>& groups = socket->GetJoinedGroups();
534 results_ = sockets_udp::GetJoinedGroups::Results::Create(groups);
535 }
536
SocketsUdpSetBroadcastFunction()537 SocketsUdpSetBroadcastFunction::SocketsUdpSetBroadcastFunction() {
538 }
539
~SocketsUdpSetBroadcastFunction()540 SocketsUdpSetBroadcastFunction::~SocketsUdpSetBroadcastFunction() {
541 }
542
Prepare()543 bool SocketsUdpSetBroadcastFunction::Prepare() {
544 params_ = api::sockets_udp::SetBroadcast::Params::Create(*args_);
545 EXTENSION_FUNCTION_VALIDATE(params_.get());
546 return true;
547 }
548
AsyncWorkStart()549 void SocketsUdpSetBroadcastFunction::AsyncWorkStart() {
550 ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
551 if (!socket) {
552 error_ = kSocketNotFoundError;
553 AsyncWorkCompleted();
554 return;
555 }
556
557 socket->SetBroadcast(
558 params_->enabled,
559 base::BindOnce(&SocketsUdpSetBroadcastFunction::OnCompleted, this));
560 }
561
OnCompleted(int net_result)562 void SocketsUdpSetBroadcastFunction::OnCompleted(int net_result) {
563 if (net_result != net::OK)
564 error_ = net::ErrorToString(net_result);
565 results_ = sockets_udp::SetBroadcast::Results::Create(net_result);
566 AsyncWorkCompleted();
567 }
568
569 } // namespace api
570 } // namespace extensions
571