Index: extensions/browser/api/socket/socket_api.cc |
diff --git a/extensions/browser/api/socket/socket_api.cc b/extensions/browser/api/socket/socket_api.cc |
index dca379ab144f381e4f4db4720eeeb230ac7b914a..20f9c62bbfb04affd948e58ac5c9e2916ce89a8a 100644 |
--- a/extensions/browser/api/socket/socket_api.cc |
+++ b/extensions/browser/api/socket/socket_api.cc |
@@ -29,6 +29,12 @@ |
#include "net/url_request/url_request_context.h" |
#include "net/url_request/url_request_context_getter.h" |
+#if defined(OS_CHROMEOS) |
+#include "base/sys_info.h" |
+#include "chromeos/network/firewall_hole.h" |
+#include "content/public/browser/browser_thread.h" |
+#endif // OS_CHROMEOS |
+ |
namespace extensions { |
using content::SocketPermissionRequest; |
@@ -52,6 +58,10 @@ const char kSocketNotConnectedError[] = "Socket not connected"; |
const char kWildcardAddress[] = "*"; |
const uint16 kWildcardPort = 0; |
+#if defined(OS_CHROMEOS) |
+const char kFirewallFailure[] = "Failed to open firewall port"; |
+#endif // OS_CHROMEOS |
+ |
SocketAsyncApiFunction::SocketAsyncApiFunction() {} |
SocketAsyncApiFunction::~SocketAsyncApiFunction() {} |
@@ -90,6 +100,73 @@ void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) { |
manager_->Remove(extension_->id(), api_resource_id); |
} |
+void SocketAsyncApiFunction::OpenFirewallHole(const std::string& address, |
+ int socket_id, |
+ Socket* socket) { |
+#if defined(OS_CHROMEOS) |
+ if (base::SysInfo::IsRunningOnChromeOS() && !net::IsLocalhost(address)) { |
+ net::IPEndPoint local_address; |
+ if (!socket->GetLocalAddress(&local_address)) { |
+ NOTREACHED() << "Cannot get address of recently bound socket."; |
+ error_ = kFirewallFailure; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ chromeos::FirewallHole::PortType port_type; |
+ if (socket->GetSocketType() == Socket::TYPE_TCP) { |
+ port_type = chromeos::FirewallHole::TCP; |
+ } else { |
+ port_type = chromeos::FirewallHole::UDP; |
+ } |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind( |
+ &chromeos::FirewallHole::Open, port_type, local_address.port(), "", |
+ base::Bind(&SocketAsyncApiFunction::OnFirewallHoleOpenedOnUIThread, |
+ this, socket_id))); |
+ return; |
+ } |
+#endif |
+ AsyncWorkCompleted(); |
+} |
+ |
+#if defined(OS_CHROMEOS) |
+ |
+void SocketAsyncApiFunction::OnFirewallHoleOpenedOnUIThread( |
+ int socket_id, |
+ scoped_ptr<chromeos::FirewallHole> hole) { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&SocketAsyncApiFunction::OnFirewallHoleOpened, this, socket_id, |
+ base::Passed(&hole))); |
+} |
+ |
+void SocketAsyncApiFunction::OnFirewallHoleOpened( |
+ int socket_id, |
+ scoped_ptr<chromeos::FirewallHole> hole) { |
+ if (!hole) { |
+ error_ = kFirewallFailure; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ Socket* socket = GetSocket(socket_id); |
+ if (!socket) { |
+ error_ = kSocketNotFoundError; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ socket->set_firewall_hole(hole.Pass()); |
+} |
+ |
+#endif // OS_CHROMEOS |
+ |
SocketExtensionWithDnsLookupFunction::SocketExtensionWithDnsLookupFunction() |
: resource_context_(NULL), |
request_handle_(new net::HostResolver::RequestHandle), |
@@ -294,33 +371,41 @@ bool SocketBindFunction::Prepare() { |
return true; |
} |
-void SocketBindFunction::Work() { |
- int result = -1; |
+void SocketBindFunction::AsyncWorkStart() { |
Socket* socket = GetSocket(socket_id_); |
- |
if (!socket) { |
error_ = kSocketNotFoundError; |
- SetResult(new base::FundamentalValue(result)); |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
return; |
} |
- if (socket->GetSocketType() == Socket::TYPE_UDP) { |
- SocketPermission::CheckParam param( |
- SocketPermissionRequest::UDP_BIND, address_, port_); |
- if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
- APIPermission::kSocket, ¶m)) { |
- error_ = kPermissionError; |
- SetResult(new base::FundamentalValue(result)); |
- return; |
- } |
- } else if (socket->GetSocketType() == Socket::TYPE_TCP) { |
+ if (socket->GetSocketType() == Socket::TYPE_TCP) { |
error_ = kTCPSocketBindError; |
- SetResult(new base::FundamentalValue(result)); |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ CHECK(socket->GetSocketType() == Socket::TYPE_UDP); |
+ SocketPermission::CheckParam param(SocketPermissionRequest::UDP_BIND, |
+ address_, port_); |
+ if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
+ APIPermission::kSocket, ¶m)) { |
+ error_ = kPermissionError; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
return; |
} |
- result = socket->Bind(address_, port_); |
+ int result = socket->Bind(address_, port_); |
SetResult(new base::FundamentalValue(result)); |
+ if (result != net::OK) { |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ OpenFirewallHole(address_, socket_id_, socket); |
} |
SocketListenFunction::SocketListenFunction() {} |
@@ -333,30 +418,35 @@ bool SocketListenFunction::Prepare() { |
return true; |
} |
-void SocketListenFunction::Work() { |
- int result = -1; |
- |
+void SocketListenFunction::AsyncWorkStart() { |
Socket* socket = GetSocket(params_->socket_id); |
- if (socket) { |
- SocketPermission::CheckParam param( |
- SocketPermissionRequest::TCP_LISTEN, params_->address, params_->port); |
- if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
- APIPermission::kSocket, ¶m)) { |
- error_ = kPermissionError; |
- SetResult(new base::FundamentalValue(result)); |
- return; |
- } |
- |
- result = |
- socket->Listen(params_->address, |
- params_->port, |
- params_->backlog.get() ? *params_->backlog.get() : 5, |
- &error_); |
- } else { |
+ if (!socket) { |
error_ = kSocketNotFoundError; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ SocketPermission::CheckParam param(SocketPermissionRequest::TCP_LISTEN, |
+ params_->address, params_->port); |
+ if (!extension()->permissions_data()->CheckAPIPermissionWithParam( |
+ APIPermission::kSocket, ¶m)) { |
+ error_ = kPermissionError; |
+ SetResult(new base::FundamentalValue(-1)); |
+ AsyncWorkCompleted(); |
+ return; |
} |
+ int result = socket->Listen( |
+ params_->address, params_->port, |
+ params_->backlog.get() ? *params_->backlog.get() : 5, &error_); |
SetResult(new base::FundamentalValue(result)); |
+ if (result != net::OK) { |
+ AsyncWorkCompleted(); |
+ return; |
+ } |
+ |
+ OpenFirewallHole(params_->address, params_->socket_id, socket); |
} |
SocketAcceptFunction::SocketAcceptFunction() {} |