| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/api/socket/socket_api.h" | 5 #include "extensions/browser/api/socket/socket_api.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/containers/hash_tables.h" | 10 #include "base/containers/hash_tables.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "extensions/common/permissions/socket_permission.h" | 22 #include "extensions/common/permissions/socket_permission.h" |
| 23 #include "net/base/host_port_pair.h" | 23 #include "net/base/host_port_pair.h" |
| 24 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
| 25 #include "net/base/ip_endpoint.h" | 25 #include "net/base/ip_endpoint.h" |
| 26 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 27 #include "net/base/net_log.h" | 27 #include "net/base/net_log.h" |
| 28 #include "net/base/net_util.h" | 28 #include "net/base/net_util.h" |
| 29 #include "net/url_request/url_request_context.h" | 29 #include "net/url_request/url_request_context.h" |
| 30 #include "net/url_request/url_request_context_getter.h" | 30 #include "net/url_request/url_request_context_getter.h" |
| 31 | 31 |
| 32 #if defined(OS_CHROMEOS) |
| 33 #include "base/command_line.h" |
| 34 #include "chromeos/chromeos_switches.h" |
| 35 #include "chromeos/network/firewall_hole.h" |
| 36 #include "content/public/browser/browser_thread.h" |
| 37 #endif // OS_CHROMEOS |
| 38 |
| 32 namespace extensions { | 39 namespace extensions { |
| 33 | 40 |
| 34 using content::SocketPermissionRequest; | 41 using content::SocketPermissionRequest; |
| 35 | 42 |
| 36 const char kAddressKey[] = "address"; | 43 const char kAddressKey[] = "address"; |
| 37 const char kPortKey[] = "port"; | 44 const char kPortKey[] = "port"; |
| 38 const char kBytesWrittenKey[] = "bytesWritten"; | 45 const char kBytesWrittenKey[] = "bytesWritten"; |
| 39 const char kDataKey[] = "data"; | 46 const char kDataKey[] = "data"; |
| 40 const char kResultCodeKey[] = "resultCode"; | 47 const char kResultCodeKey[] = "resultCode"; |
| 41 const char kSocketIdKey[] = "socketId"; | 48 const char kSocketIdKey[] = "socketId"; |
| 42 | 49 |
| 43 const char kSocketNotFoundError[] = "Socket not found"; | 50 const char kSocketNotFoundError[] = "Socket not found"; |
| 44 const char kDnsLookupFailedError[] = "DNS resolution failed"; | 51 const char kDnsLookupFailedError[] = "DNS resolution failed"; |
| 45 const char kPermissionError[] = "App does not have permission"; | 52 const char kPermissionError[] = "App does not have permission"; |
| 46 const char kNetworkListError[] = "Network lookup failed or unsupported"; | 53 const char kNetworkListError[] = "Network lookup failed or unsupported"; |
| 47 const char kTCPSocketBindError[] = | 54 const char kTCPSocketBindError[] = |
| 48 "TCP socket does not support bind. For TCP server please use listen."; | 55 "TCP socket does not support bind. For TCP server please use listen."; |
| 49 const char kMulticastSocketTypeError[] = "Only UDP socket supports multicast."; | 56 const char kMulticastSocketTypeError[] = "Only UDP socket supports multicast."; |
| 50 const char kSecureSocketTypeError[] = "Only TCP sockets are supported for TLS."; | 57 const char kSecureSocketTypeError[] = "Only TCP sockets are supported for TLS."; |
| 51 const char kSocketNotConnectedError[] = "Socket not connected"; | 58 const char kSocketNotConnectedError[] = "Socket not connected"; |
| 52 const char kWildcardAddress[] = "*"; | 59 const char kWildcardAddress[] = "*"; |
| 53 const uint16 kWildcardPort = 0; | 60 const uint16 kWildcardPort = 0; |
| 54 | 61 |
| 62 #if defined(OS_CHROMEOS) |
| 63 const char kFirewallFailure[] = "Failed to open firewall port"; |
| 64 #endif // OS_CHROMEOS |
| 65 |
| 55 SocketAsyncApiFunction::SocketAsyncApiFunction() {} | 66 SocketAsyncApiFunction::SocketAsyncApiFunction() {} |
| 56 | 67 |
| 57 SocketAsyncApiFunction::~SocketAsyncApiFunction() {} | 68 SocketAsyncApiFunction::~SocketAsyncApiFunction() {} |
| 58 | 69 |
| 59 bool SocketAsyncApiFunction::PrePrepare() { | 70 bool SocketAsyncApiFunction::PrePrepare() { |
| 60 manager_ = CreateSocketResourceManager(); | 71 manager_ = CreateSocketResourceManager(); |
| 61 return manager_->SetBrowserContext(browser_context()); | 72 return manager_->SetBrowserContext(browser_context()); |
| 62 } | 73 } |
| 63 | 74 |
| 64 bool SocketAsyncApiFunction::Respond() { return error_.empty(); } | 75 bool SocketAsyncApiFunction::Respond() { return error_.empty(); } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 83 } | 94 } |
| 84 | 95 |
| 85 base::hash_set<int>* SocketAsyncApiFunction::GetSocketIds() { | 96 base::hash_set<int>* SocketAsyncApiFunction::GetSocketIds() { |
| 86 return manager_->GetResourceIds(extension_->id()); | 97 return manager_->GetResourceIds(extension_->id()); |
| 87 } | 98 } |
| 88 | 99 |
| 89 void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) { | 100 void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) { |
| 90 manager_->Remove(extension_->id(), api_resource_id); | 101 manager_->Remove(extension_->id(), api_resource_id); |
| 91 } | 102 } |
| 92 | 103 |
| 104 void SocketAsyncApiFunction::OpenFirewallHole(const std::string& address, |
| 105 int socket_id, |
| 106 Socket* socket) { |
| 107 #if defined(OS_CHROMEOS) |
| 108 if (!net::IsLocalhost(address) && |
| 109 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 110 chromeos::switches::kEnableFirewallHolePunching)) { |
| 111 net::IPEndPoint local_address; |
| 112 if (!socket->GetLocalAddress(&local_address)) { |
| 113 NOTREACHED() << "Cannot get address of recently bound socket."; |
| 114 error_ = kFirewallFailure; |
| 115 SetResult(new base::FundamentalValue(-1)); |
| 116 AsyncWorkCompleted(); |
| 117 return; |
| 118 } |
| 119 |
| 120 chromeos::FirewallHole::PortType port_type; |
| 121 if (socket->GetSocketType() == Socket::TYPE_TCP) { |
| 122 port_type = chromeos::FirewallHole::PortType::TCP; |
| 123 } else { |
| 124 port_type = chromeos::FirewallHole::PortType::UDP; |
| 125 } |
| 126 |
| 127 content::BrowserThread::PostTask( |
| 128 content::BrowserThread::UI, FROM_HERE, |
| 129 base::Bind( |
| 130 &chromeos::FirewallHole::Open, port_type, local_address.port(), |
| 131 "" /* all interfaces */, |
| 132 base::Bind(&SocketAsyncApiFunction::OnFirewallHoleOpenedOnUIThread, |
| 133 this, socket_id))); |
| 134 return; |
| 135 } |
| 136 #endif |
| 137 AsyncWorkCompleted(); |
| 138 } |
| 139 |
| 140 #if defined(OS_CHROMEOS) |
| 141 |
| 142 void SocketAsyncApiFunction::OnFirewallHoleOpenedOnUIThread( |
| 143 int socket_id, |
| 144 scoped_ptr<chromeos::FirewallHole> hole) { |
| 145 content::BrowserThread::PostTask( |
| 146 content::BrowserThread::IO, FROM_HERE, |
| 147 base::Bind(&SocketAsyncApiFunction::OnFirewallHoleOpened, this, socket_id, |
| 148 base::Passed(&hole))); |
| 149 } |
| 150 |
| 151 void SocketAsyncApiFunction::OnFirewallHoleOpened( |
| 152 int socket_id, |
| 153 scoped_ptr<chromeos::FirewallHole> hole) { |
| 154 if (!hole) { |
| 155 error_ = kFirewallFailure; |
| 156 SetResult(new base::FundamentalValue(-1)); |
| 157 AsyncWorkCompleted(); |
| 158 return; |
| 159 } |
| 160 |
| 161 Socket* socket = GetSocket(socket_id); |
| 162 if (!socket) { |
| 163 error_ = kSocketNotFoundError; |
| 164 SetResult(new base::FundamentalValue(-1)); |
| 165 AsyncWorkCompleted(); |
| 166 return; |
| 167 } |
| 168 |
| 169 socket->set_firewall_hole(hole.Pass()); |
| 170 AsyncWorkCompleted(); |
| 171 } |
| 172 |
| 173 #endif // OS_CHROMEOS |
| 174 |
| 93 SocketExtensionWithDnsLookupFunction::SocketExtensionWithDnsLookupFunction() | 175 SocketExtensionWithDnsLookupFunction::SocketExtensionWithDnsLookupFunction() |
| 94 : resource_context_(NULL), | 176 : resource_context_(NULL), |
| 95 request_handle_(new net::HostResolver::RequestHandle), | 177 request_handle_(new net::HostResolver::RequestHandle), |
| 96 addresses_(new net::AddressList) {} | 178 addresses_(new net::AddressList) {} |
| 97 | 179 |
| 98 SocketExtensionWithDnsLookupFunction::~SocketExtensionWithDnsLookupFunction() {} | 180 SocketExtensionWithDnsLookupFunction::~SocketExtensionWithDnsLookupFunction() {} |
| 99 | 181 |
| 100 bool SocketExtensionWithDnsLookupFunction::PrePrepare() { | 182 bool SocketExtensionWithDnsLookupFunction::PrePrepare() { |
| 101 if (!SocketAsyncApiFunction::PrePrepare()) | 183 if (!SocketAsyncApiFunction::PrePrepare()) |
| 102 return false; | 184 return false; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 bool SocketBindFunction::Prepare() { | 369 bool SocketBindFunction::Prepare() { |
| 288 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_)); | 370 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_)); |
| 289 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &address_)); | 371 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &address_)); |
| 290 int port; | 372 int port; |
| 291 EXTENSION_FUNCTION_VALIDATE( | 373 EXTENSION_FUNCTION_VALIDATE( |
| 292 args_->GetInteger(2, &port) && port >= 0 && port <= 65535); | 374 args_->GetInteger(2, &port) && port >= 0 && port <= 65535); |
| 293 port_ = static_cast<uint16>(port); | 375 port_ = static_cast<uint16>(port); |
| 294 return true; | 376 return true; |
| 295 } | 377 } |
| 296 | 378 |
| 297 void SocketBindFunction::Work() { | 379 void SocketBindFunction::AsyncWorkStart() { |
| 298 int result = -1; | |
| 299 Socket* socket = GetSocket(socket_id_); | 380 Socket* socket = GetSocket(socket_id_); |
| 300 | |
| 301 if (!socket) { | 381 if (!socket) { |
| 302 error_ = kSocketNotFoundError; | 382 error_ = kSocketNotFoundError; |
| 303 SetResult(new base::FundamentalValue(result)); | 383 SetResult(new base::FundamentalValue(-1)); |
| 384 AsyncWorkCompleted(); |
| 304 return; | 385 return; |
| 305 } | 386 } |
| 306 | 387 |
| 307 if (socket->GetSocketType() == Socket::TYPE_UDP) { | 388 if (socket->GetSocketType() == Socket::TYPE_TCP) { |
| 308 SocketPermission::CheckParam param( | |
| 309 SocketPermissionRequest::UDP_BIND, address_, port_); | |
| 310 if (!extension()->permissions_data()->CheckAPIPermissionWithParam( | |
| 311 APIPermission::kSocket, ¶m)) { | |
| 312 error_ = kPermissionError; | |
| 313 SetResult(new base::FundamentalValue(result)); | |
| 314 return; | |
| 315 } | |
| 316 } else if (socket->GetSocketType() == Socket::TYPE_TCP) { | |
| 317 error_ = kTCPSocketBindError; | 389 error_ = kTCPSocketBindError; |
| 318 SetResult(new base::FundamentalValue(result)); | 390 SetResult(new base::FundamentalValue(-1)); |
| 391 AsyncWorkCompleted(); |
| 319 return; | 392 return; |
| 320 } | 393 } |
| 321 | 394 |
| 322 result = socket->Bind(address_, port_); | 395 CHECK(socket->GetSocketType() == Socket::TYPE_UDP); |
| 396 SocketPermission::CheckParam param(SocketPermissionRequest::UDP_BIND, |
| 397 address_, port_); |
| 398 if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
| 399 APIPermission::kSocket, ¶m)) { |
| 400 error_ = kPermissionError; |
| 401 SetResult(new base::FundamentalValue(-1)); |
| 402 AsyncWorkCompleted(); |
| 403 return; |
| 404 } |
| 405 |
| 406 int result = socket->Bind(address_, port_); |
| 323 SetResult(new base::FundamentalValue(result)); | 407 SetResult(new base::FundamentalValue(result)); |
| 408 if (result != net::OK) { |
| 409 AsyncWorkCompleted(); |
| 410 return; |
| 411 } |
| 412 |
| 413 OpenFirewallHole(address_, socket_id_, socket); |
| 324 } | 414 } |
| 325 | 415 |
| 326 SocketListenFunction::SocketListenFunction() {} | 416 SocketListenFunction::SocketListenFunction() {} |
| 327 | 417 |
| 328 SocketListenFunction::~SocketListenFunction() {} | 418 SocketListenFunction::~SocketListenFunction() {} |
| 329 | 419 |
| 330 bool SocketListenFunction::Prepare() { | 420 bool SocketListenFunction::Prepare() { |
| 331 params_ = core_api::socket::Listen::Params::Create(*args_); | 421 params_ = core_api::socket::Listen::Params::Create(*args_); |
| 332 EXTENSION_FUNCTION_VALIDATE(params_.get()); | 422 EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| 333 return true; | 423 return true; |
| 334 } | 424 } |
| 335 | 425 |
| 336 void SocketListenFunction::Work() { | 426 void SocketListenFunction::AsyncWorkStart() { |
| 337 int result = -1; | |
| 338 | |
| 339 Socket* socket = GetSocket(params_->socket_id); | 427 Socket* socket = GetSocket(params_->socket_id); |
| 340 if (socket) { | 428 if (!socket) { |
| 341 SocketPermission::CheckParam param( | |
| 342 SocketPermissionRequest::TCP_LISTEN, params_->address, params_->port); | |
| 343 if (!extension()->permissions_data()->CheckAPIPermissionWithParam( | |
| 344 APIPermission::kSocket, ¶m)) { | |
| 345 error_ = kPermissionError; | |
| 346 SetResult(new base::FundamentalValue(result)); | |
| 347 return; | |
| 348 } | |
| 349 | |
| 350 result = | |
| 351 socket->Listen(params_->address, | |
| 352 params_->port, | |
| 353 params_->backlog.get() ? *params_->backlog.get() : 5, | |
| 354 &error_); | |
| 355 } else { | |
| 356 error_ = kSocketNotFoundError; | 429 error_ = kSocketNotFoundError; |
| 430 SetResult(new base::FundamentalValue(-1)); |
| 431 AsyncWorkCompleted(); |
| 432 return; |
| 357 } | 433 } |
| 358 | 434 |
| 435 SocketPermission::CheckParam param(SocketPermissionRequest::TCP_LISTEN, |
| 436 params_->address, params_->port); |
| 437 if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
| 438 APIPermission::kSocket, ¶m)) { |
| 439 error_ = kPermissionError; |
| 440 SetResult(new base::FundamentalValue(-1)); |
| 441 AsyncWorkCompleted(); |
| 442 return; |
| 443 } |
| 444 |
| 445 int result = socket->Listen( |
| 446 params_->address, params_->port, |
| 447 params_->backlog.get() ? *params_->backlog.get() : 5, &error_); |
| 359 SetResult(new base::FundamentalValue(result)); | 448 SetResult(new base::FundamentalValue(result)); |
| 449 if (result != net::OK) { |
| 450 AsyncWorkCompleted(); |
| 451 return; |
| 452 } |
| 453 |
| 454 OpenFirewallHole(params_->address, params_->socket_id, socket); |
| 360 } | 455 } |
| 361 | 456 |
| 362 SocketAcceptFunction::SocketAcceptFunction() {} | 457 SocketAcceptFunction::SocketAcceptFunction() {} |
| 363 | 458 |
| 364 SocketAcceptFunction::~SocketAcceptFunction() {} | 459 SocketAcceptFunction::~SocketAcceptFunction() {} |
| 365 | 460 |
| 366 bool SocketAcceptFunction::Prepare() { | 461 bool SocketAcceptFunction::Prepare() { |
| 367 params_ = core_api::socket::Accept::Params::Create(*args_); | 462 params_ = core_api::socket::Accept::Params::Create(*args_); |
| 368 EXTENSION_FUNCTION_VALIDATE(params_.get()); | 463 EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| 369 return true; | 464 return true; |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 } else { | 1089 } else { |
| 995 RemoveSocket(params_->socket_id); | 1090 RemoveSocket(params_->socket_id); |
| 996 error_ = net::ErrorToString(result); | 1091 error_ = net::ErrorToString(result); |
| 997 } | 1092 } |
| 998 | 1093 |
| 999 results_ = core_api::socket::Secure::Results::Create(result); | 1094 results_ = core_api::socket::Secure::Results::Create(result); |
| 1000 AsyncWorkCompleted(); | 1095 AsyncWorkCompleted(); |
| 1001 } | 1096 } |
| 1002 | 1097 |
| 1003 } // namespace extensions | 1098 } // namespace extensions |
| OLD | NEW |