|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "mojo/services/network/tcp_bound_socket_impl.h" | 
|  |  | 
|  | #include "mojo/services/network/net_adapters.h" | 
|  | #include "mojo/services/network/net_address_type_converters.h" | 
|  | #include "mojo/services/network/tcp_connected_socket_impl.h" | 
|  | #include "mojo/services/network/tcp_server_socket_impl.h" | 
|  | #include "net/base/net_errors.h" | 
|  |  | 
|  | namespace mojo { | 
|  |  | 
|  | TCPBoundSocketImpl::TCPBoundSocketImpl() { | 
|  | } | 
|  |  | 
|  | TCPBoundSocketImpl::~TCPBoundSocketImpl() { | 
|  | } | 
|  |  | 
|  | int TCPBoundSocketImpl::Bind(NetAddressPtr local_address) { | 
|  | net::IPEndPoint end_point = local_address.To<net::IPEndPoint>(); | 
|  |  | 
|  | socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source())); | 
|  | int result = socket_->Open(end_point.GetFamily()); | 
|  | if (result != net::OK) | 
|  | return result; | 
|  |  | 
|  | result = socket_->SetDefaultOptionsForServer(); | 
|  | if (result != net::OK) | 
|  | return result; | 
|  |  | 
|  | result = socket_->Bind(end_point); | 
|  | if (result != net::OK) | 
|  | return result; | 
|  |  | 
|  | return net::OK; | 
|  | } | 
|  |  | 
|  | NetAddressPtr TCPBoundSocketImpl::GetLocalAddress() const { | 
|  | net::IPEndPoint resolved_local_address; | 
|  | if (socket_->GetLocalAddress(&resolved_local_address) != net::OK) | 
|  | return NetAddressPtr(); | 
|  | return NetAddress::From(resolved_local_address); | 
|  | } | 
|  |  | 
|  | void TCPBoundSocketImpl::StartListening( | 
|  | InterfaceRequest<TCPServerSocket> server, | 
|  | const Callback<void(NetworkErrorPtr)>& callback) { | 
|  | if (!socket_ || pending_connect_socket_.is_pending()) { | 
|  | // A bound socket will only be returned to the caller after binding | 
|  | // succeeds, so if the socket doesn't exist, that means ownership was | 
|  | // already passed to a server socket or client socket. | 
|  | callback.Run(MakeNetworkError(net::ERR_FAILED)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // TODO(brettw) set the backlog properly. | 
|  | int result = socket_->Listen(4); | 
|  | if (result != net::OK) { | 
|  | callback.Run(MakeNetworkError(result)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // The server socket object takes ownership of the socket. | 
|  | BindToRequest(new TCPServerSocketImpl(socket_.Pass()), &server); | 
|  | callback.Run(MakeNetworkError(net::OK)); | 
|  | } | 
|  |  | 
|  | void TCPBoundSocketImpl::Connect( | 
|  | NetAddressPtr remote_address, | 
|  | ScopedDataPipeConsumerHandle send_stream, | 
|  | ScopedDataPipeProducerHandle receive_stream, | 
|  | InterfaceRequest<TCPConnectedSocket> client_socket, | 
|  | const Callback<void(NetworkErrorPtr)>& callback) { | 
|  | if (!socket_ || pending_connect_socket_.is_pending()) { | 
|  | // A bound socket will only be returned to the caller after binding | 
|  | // succeeds, so if the socket doesn't exist, that means ownership was | 
|  | // already passed to a server socket or client socket. | 
|  | callback.Run(MakeNetworkError(net::ERR_FAILED)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | net::IPEndPoint end_point = remote_address.To<net::IPEndPoint>(); | 
|  |  | 
|  | pending_connect_send_stream_ = send_stream.Pass(); | 
|  | pending_connect_receive_stream_ = receive_stream.Pass(); | 
|  | pending_connect_socket_ = client_socket.Pass(); | 
|  | pending_connect_callback_ = callback; | 
|  | int result = socket_->Connect( | 
|  | end_point, | 
|  | base::Bind(&TCPBoundSocketImpl::OnConnected, base::Unretained(this))); | 
|  | if (result == net::OK) { | 
|  | OnConnected(result); | 
|  | } else if (result != net::ERR_IO_PENDING) { | 
|  | // Error occurred. | 
|  | pending_connect_send_stream_.reset(); | 
|  | pending_connect_receive_stream_.reset(); | 
|  | pending_connect_socket_ = InterfaceRequest<TCPConnectedSocket>(); | 
|  | pending_connect_callback_ = Callback<void(NetworkErrorPtr)>(); | 
|  | callback.Run(MakeNetworkError(result)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void TCPBoundSocketImpl::OnConnected(int result) { | 
|  | if (result == net::OK) { | 
|  | BindToRequest(new TCPConnectedSocketImpl( | 
|  | socket_.Pass(), | 
|  | pending_connect_send_stream_.Pass(), | 
|  | pending_connect_receive_stream_.Pass()), | 
|  | &pending_connect_socket_); | 
|  | } else { | 
|  | pending_connect_send_stream_.reset(); | 
|  | pending_connect_receive_stream_.reset(); | 
|  | pending_connect_socket_ = InterfaceRequest<TCPConnectedSocket>(); | 
|  | } | 
|  | pending_connect_callback_.Run(MakeNetworkError(result)); | 
|  | pending_connect_callback_ = Callback<void(NetworkErrorPtr)>(); | 
|  | } | 
|  |  | 
|  | }  // namespace mojo |