Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6814)

Unified Diff: chrome/browser/extensions/api/socket/tcp_socket.cc

Issue 10827390: Implement chrome.socket.bind/listen/accept for TCP server socket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/socket/tcp_socket.cc
diff --git a/chrome/browser/extensions/api/socket/tcp_socket.cc b/chrome/browser/extensions/api/socket/tcp_socket.cc
index 871567dbbd5f372bc2d850ef17f9362c7e682f7a..00287a54f4630743ab50ec4071d0a0076a81e129 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket.cc
+++ b/chrome/browser/extensions/api/socket/tcp_socket.cc
@@ -15,14 +15,27 @@
namespace extensions {
TCPSocket::TCPSocket(ApiResourceEventNotifier* event_notifier)
- : Socket(event_notifier) {
+ : Socket(event_notifier),
+ is_client_socket_(false),
+ is_server_socket_(false) {
+}
+
+TCPSocket::TCPSocket(ApiResourceEventNotifier* event_notifier,
+ net::TCPClientSocket* client_socket)
+ : Socket(event_notifier),
+ socket_(client_socket),
+ is_client_socket_(true),
+ is_server_socket_(false) {
+ this->is_connected_ = true;
}
// For testing.
TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
ApiResourceEventNotifier* event_notifier)
: Socket(event_notifier),
- socket_(tcp_client_socket) {
+ socket_(tcp_client_socket),
+ is_client_socket_(false),
+ is_server_socket_(false) {
}
// static
@@ -43,11 +56,15 @@ void TCPSocket::Connect(const std::string& address,
const CompletionCallback& callback) {
DCHECK(!callback.is_null());
- if (!connect_callback_.is_null()) {
+ if (!connect_callback_.is_null() || is_server_socket_) {
callback.Run(net::ERR_CONNECTION_FAILED);
return;
}
+ DCHECK(server_socket_.get() == NULL);
+ is_client_socket_ = true;
connect_callback_ = callback;
+ // TODO(justinlin): I think this should destroy any previously connected
+ // socket, otherwise we might run into binding issues.
int result = net::ERR_CONNECTION_FAILED;
do {
@@ -62,6 +79,15 @@ void TCPSocket::Connect(const std::string& address,
socket_.reset(new net::TCPClientSocket(address_list, NULL,
net::NetLog::Source()));
+
+ if (bind_address_.get() != NULL) {
+ if (socket_->Bind(*bind_address_) != 0) {
+ socket_.reset();
+ OnConnectComplete(net::ERR_ADDRESS_IN_USE);
+ return;
+ };
+ }
+
connect_callback_ = callback;
result = socket_->Connect(base::Bind(
&TCPSocket::OnConnectComplete, base::Unretained(this)));
@@ -77,14 +103,28 @@ void TCPSocket::Disconnect() {
}
int TCPSocket::Bind(const std::string& address, int port) {
- // TODO(penghuang): Supports bind for tcp?
- return net::ERR_FAILED;
+ // TODO(justinlin): Allow binding to multiple interfaces?
+ if (bind_address_.get() != NULL) {
+ return net::ERR_FAILED;
+ }
+
+ scoped_ptr<net::IPEndPoint> ip_end_point(new net::IPEndPoint());
+ if (!StringAndPortToIPEndPoint(address, port, ip_end_point.get()))
+ return net::ERR_INVALID_ARGUMENT;
+
+ bind_address_.swap(ip_end_point);
+ return true;
}
void TCPSocket::Read(int count,
const ReadCompletionCallback& callback) {
DCHECK(!callback.is_null());
+ if (!is_client_socket_) {
+ callback.Run(net::ERR_FAILED, NULL);
+ return;
+ }
+
if (!read_callback_.is_null()) {
callback.Run(net::ERR_IO_PENDING, NULL);
return;
@@ -140,6 +180,51 @@ bool TCPSocket::SetNoDelay(bool no_delay) {
return socket_->SetNoDelay(no_delay);
}
+bool TCPSocket::Listen(int backlog) {
+ if (is_client_socket_) {
+ return false;
miket_OOO 2012/08/31 23:18:01 An error message would be nice.
justinlin 2012/09/11 04:32:32 Done.
+ }
+ DCHECK(socket_.get() == NULL);
+ is_server_socket_ = true;
+
+ if (bind_address_.get() == NULL) {
+ return net::ERR_FAILED;
+ }
+
+ server_socket_.reset(new net::TCPServerSocket(NULL,
+ net::NetLog::Source()));
+ return server_socket_->Listen(*bind_address_, backlog);
+}
+
+void TCPSocket::Accept(const AcceptCompletionCallback &callback) {
+ // This also makes it so you can't accept before listening, but that's
+ // probably OK?
+ if (!is_server_socket_ || server_socket_.get() == NULL) {
+ callback.Run(net::ERR_FAILED, NULL);
+ return;
+ }
+
+ // Limits to only 1 blocked accept call.
miket_OOO 2012/08/31 23:18:01 Should this be a TODO to allow multiple? (I'm not
justinlin 2012/09/11 04:32:32 Yea, the number of connections held in the queue i
+ if (!accept_callback_.is_null()) {
+ callback.Run(net::ERR_FAILED, NULL);
+ return;
+ }
+
+ int result = server_socket_->Accept(&accept_socket_, base::Bind(
+ &TCPSocket::OnAccept, base::Unretained(this)));
+ if (result == net::ERR_IO_PENDING) {
+ accept_callback_ = callback;
+ return;
+ } else if (result == net::OK) {
+ accept_callback_ = callback;
+ this->OnAccept(result);
+ return;
+ } else {
+ callback.Run(result, NULL);
+ return;
+ }
+}
+
bool TCPSocket::IsTCPSocket() {
return true;
}
@@ -151,16 +236,22 @@ bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
}
bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
- if (!socket_.get())
+ if (socket_.get() != NULL) {
+ return !socket_->GetLocalAddress(address);
+ } else if (server_socket_.get() != NULL) {
+ return !server_socket_->GetLocalAddress(address);
+ } else {
return false;
- return !socket_->GetLocalAddress(address);
+ }
}
int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
int io_buffer_size,
const net::CompletionCallback& callback) {
- if (!socket_.get() || !socket_->IsConnected())
+ if (!is_client_socket_) {
+ return net::ERR_FAILED;
+ } else if (!socket_.get() || !socket_->IsConnected())
return net::ERR_SOCKET_NOT_CONNECTED;
else
return socket_->Write(io_buffer, io_buffer_size, callback);
@@ -181,4 +272,17 @@ void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
read_callback_.Reset();
}
+void TCPSocket::OnAccept(int result) {
+ DCHECK(!accept_callback_.is_null());
+ if (result == net::OK) {
+ DCHECK(accept_socket_.get() != NULL);
+
+ accept_callback_.Run(
+ result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
+ } else {
+ accept_callback_.Run(result, NULL);
+ }
+ accept_callback_.Reset();
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698