tcp_connected_socket.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright 2018 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. #include "services/network/tcp_connected_socket.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/check_op.h"
  8. #include "base/cxx17_backports.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "net/base/net_errors.h"
  11. #include "net/log/net_log.h"
  12. #include "net/socket/client_socket_factory.h"
  13. #include "net/socket/client_socket_handle.h"
  14. #include "services/network/public/mojom/tcp_socket.mojom.h"
  15. #include "services/network/tls_client_socket.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. namespace network {
  18. namespace {
  19. int ClampTCPBufferSize(int requested_buffer_size) {
  20. return base::clamp(requested_buffer_size, 0,
  21. TCPConnectedSocket::kMaxBufferSize);
  22. }
  23. // Sets the initial options on a fresh socket. Assumes |socket| is currently
  24. // configured using the default client socket options
  25. // (TCPSocket::SetDefaultOptionsForClient()).
  26. int ConfigureSocket(
  27. net::TransportClientSocket* socket,
  28. const mojom::TCPConnectedSocketOptions* tcp_connected_socket_options) {
  29. int send_buffer_size =
  30. ClampTCPBufferSize(tcp_connected_socket_options->send_buffer_size);
  31. if (send_buffer_size > 0) {
  32. int result = socket->SetSendBufferSize(send_buffer_size);
  33. DCHECK_NE(net::ERR_IO_PENDING, result);
  34. if (result != net::OK)
  35. return result;
  36. }
  37. int receive_buffer_size =
  38. ClampTCPBufferSize(tcp_connected_socket_options->receive_buffer_size);
  39. if (receive_buffer_size > 0) {
  40. int result = socket->SetReceiveBufferSize(receive_buffer_size);
  41. DCHECK_NE(net::ERR_IO_PENDING, result);
  42. if (result != net::OK)
  43. return result;
  44. }
  45. // No delay is set by default, so only update the setting if it's false.
  46. if (!tcp_connected_socket_options->no_delay) {
  47. // Unlike the above calls, TcpSocket::SetNoDelay() returns a bool rather
  48. // than a network error code.
  49. if (!socket->SetNoDelay(false))
  50. return net::ERR_FAILED;
  51. }
  52. const mojom::TCPKeepAliveOptionsPtr& keep_alive_options =
  53. tcp_connected_socket_options->keep_alive_options;
  54. if (keep_alive_options) {
  55. // TcpSocket::SetKeepAlive(...) returns a bool rather than a network error
  56. // code.
  57. if (!socket->SetKeepAlive(/*enable=*/keep_alive_options->enable,
  58. /*delay_secs=*/keep_alive_options->delay)) {
  59. return net::ERR_FAILED;
  60. }
  61. }
  62. return net::OK;
  63. }
  64. } // namespace
  65. const int TCPConnectedSocket::kMaxBufferSize = 128 * 1024;
  66. TCPConnectedSocket::TCPConnectedSocket(
  67. mojo::PendingRemote<mojom::SocketObserver> observer,
  68. net::NetLog* net_log,
  69. TLSSocketFactory* tls_socket_factory,
  70. net::ClientSocketFactory* client_socket_factory,
  71. const net::NetworkTrafficAnnotationTag& traffic_annotation)
  72. : observer_(std::move(observer)),
  73. net_log_(net_log),
  74. client_socket_factory_(client_socket_factory),
  75. tls_socket_factory_(tls_socket_factory),
  76. traffic_annotation_(traffic_annotation) {}
  77. TCPConnectedSocket::TCPConnectedSocket(
  78. mojo::PendingRemote<mojom::SocketObserver> observer,
  79. std::unique_ptr<net::TransportClientSocket> socket,
  80. mojo::ScopedDataPipeProducerHandle receive_pipe_handle,
  81. mojo::ScopedDataPipeConsumerHandle send_pipe_handle,
  82. const net::NetworkTrafficAnnotationTag& traffic_annotation)
  83. : observer_(std::move(observer)),
  84. net_log_(nullptr),
  85. client_socket_factory_(nullptr),
  86. tls_socket_factory_(nullptr),
  87. socket_(std::move(socket)),
  88. traffic_annotation_(traffic_annotation) {
  89. socket_data_pump_ = std::make_unique<SocketDataPump>(
  90. socket_.get(), this /*delegate*/, std::move(receive_pipe_handle),
  91. std::move(send_pipe_handle), traffic_annotation);
  92. }
  93. TCPConnectedSocket::~TCPConnectedSocket() {
  94. if (connect_callback_) {
  95. // If |this| is destroyed when connect hasn't completed, tell the consumer
  96. // that request has been aborted.
  97. std::move(connect_callback_)
  98. .Run(net::ERR_ABORTED, absl::nullopt, absl::nullopt,
  99. mojo::ScopedDataPipeConsumerHandle(),
  100. mojo::ScopedDataPipeProducerHandle());
  101. }
  102. }
  103. void TCPConnectedSocket::Connect(
  104. const absl::optional<net::IPEndPoint>& local_addr,
  105. const net::AddressList& remote_addr_list,
  106. mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
  107. mojom::NetworkContext::CreateTCPConnectedSocketCallback callback) {
  108. DCHECK(!socket_);
  109. DCHECK(callback);
  110. // TODO(https://crbug.com/1123197): Pass a non-null NetworkQualityEstimator.
  111. net::NetworkQualityEstimator* network_quality_estimator = nullptr;
  112. std::unique_ptr<net::TransportClientSocket> socket =
  113. client_socket_factory_->CreateTransportClientSocket(
  114. remote_addr_list, nullptr /*socket_performance_watcher*/,
  115. network_quality_estimator, net_log_, net::NetLogSource());
  116. if (local_addr) {
  117. int result = socket->Bind(local_addr.value());
  118. if (result != net::OK) {
  119. OnConnectCompleted(result);
  120. return;
  121. }
  122. }
  123. return ConnectWithSocket(std::move(socket),
  124. std::move(tcp_connected_socket_options),
  125. std::move(callback));
  126. }
  127. void TCPConnectedSocket::ConnectWithSocket(
  128. std::unique_ptr<net::TransportClientSocket> socket,
  129. mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
  130. mojom::NetworkContext::CreateTCPConnectedSocketCallback callback) {
  131. socket_ = std::move(socket);
  132. connect_callback_ = std::move(callback);
  133. if (tcp_connected_socket_options) {
  134. socket_options_ = std::move(tcp_connected_socket_options);
  135. socket_->SetBeforeConnectCallback(base::BindRepeating(
  136. &ConfigureSocket, socket_.get(), socket_options_.get()));
  137. }
  138. int result = socket_->Connect(base::BindOnce(
  139. &TCPConnectedSocket::OnConnectCompleted, base::Unretained(this)));
  140. if (result == net::ERR_IO_PENDING)
  141. return;
  142. OnConnectCompleted(result);
  143. }
  144. void TCPConnectedSocket::UpgradeToTLS(
  145. const net::HostPortPair& host_port_pair,
  146. mojom::TLSClientSocketOptionsPtr socket_options,
  147. const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
  148. mojo::PendingReceiver<mojom::TLSClientSocket> receiver,
  149. mojo::PendingRemote<mojom::SocketObserver> observer,
  150. mojom::TCPConnectedSocket::UpgradeToTLSCallback callback) {
  151. if (!tls_socket_factory_) {
  152. std::move(callback).Run(
  153. net::ERR_NOT_IMPLEMENTED, mojo::ScopedDataPipeConsumerHandle(),
  154. mojo::ScopedDataPipeProducerHandle(), absl::nullopt /* ssl_info*/);
  155. return;
  156. }
  157. // Wait for data pipes to be closed by the client before doing the upgrade.
  158. if (socket_data_pump_) {
  159. pending_upgrade_to_tls_callback_ = base::BindOnce(
  160. &TCPConnectedSocket::UpgradeToTLS, base::Unretained(this),
  161. host_port_pair, std::move(socket_options), traffic_annotation,
  162. std::move(receiver), std::move(observer), std::move(callback));
  163. return;
  164. }
  165. tls_socket_factory_->UpgradeToTLS(
  166. this, host_port_pair, std::move(socket_options), traffic_annotation,
  167. std::move(receiver), std::move(observer), std::move(callback));
  168. }
  169. void TCPConnectedSocket::SetSendBufferSize(int send_buffer_size,
  170. SetSendBufferSizeCallback callback) {
  171. if (!socket_) {
  172. // Fail is this method was called after upgrading to TLS.
  173. std::move(callback).Run(net::ERR_UNEXPECTED);
  174. return;
  175. }
  176. int result = socket_->SetSendBufferSize(ClampTCPBufferSize(send_buffer_size));
  177. std::move(callback).Run(result);
  178. }
  179. void TCPConnectedSocket::SetReceiveBufferSize(
  180. int send_buffer_size,
  181. SetSendBufferSizeCallback callback) {
  182. if (!socket_) {
  183. // Fail is this method was called after upgrading to TLS.
  184. std::move(callback).Run(net::ERR_UNEXPECTED);
  185. return;
  186. }
  187. int result =
  188. socket_->SetReceiveBufferSize(ClampTCPBufferSize(send_buffer_size));
  189. std::move(callback).Run(result);
  190. }
  191. void TCPConnectedSocket::SetNoDelay(bool no_delay,
  192. SetNoDelayCallback callback) {
  193. if (!socket_) {
  194. std::move(callback).Run(false);
  195. return;
  196. }
  197. bool success = socket_->SetNoDelay(no_delay);
  198. std::move(callback).Run(success);
  199. }
  200. void TCPConnectedSocket::SetKeepAlive(bool enable,
  201. int32_t delay_secs,
  202. SetKeepAliveCallback callback) {
  203. if (!socket_) {
  204. std::move(callback).Run(false);
  205. return;
  206. }
  207. bool success = socket_->SetKeepAlive(enable, delay_secs);
  208. std::move(callback).Run(success);
  209. }
  210. void TCPConnectedSocket::OnConnectCompleted(int result) {
  211. DCHECK(!connect_callback_.is_null());
  212. DCHECK(!socket_data_pump_);
  213. net::IPEndPoint peer_addr, local_addr;
  214. if (result == net::OK)
  215. result = socket_->GetLocalAddress(&local_addr);
  216. if (result == net::OK)
  217. result = socket_->GetPeerAddress(&peer_addr);
  218. mojo::ScopedDataPipeProducerHandle send_producer_handle;
  219. mojo::ScopedDataPipeConsumerHandle send_consumer_handle;
  220. if (result == net::OK) {
  221. if (mojo::CreateDataPipe(nullptr, send_producer_handle,
  222. send_consumer_handle) != MOJO_RESULT_OK) {
  223. result = net::ERR_FAILED;
  224. }
  225. }
  226. mojo::ScopedDataPipeProducerHandle receive_producer_handle;
  227. mojo::ScopedDataPipeConsumerHandle receive_consumer_handle;
  228. if (result == net::OK) {
  229. if (mojo::CreateDataPipe(nullptr, receive_producer_handle,
  230. receive_consumer_handle) != MOJO_RESULT_OK) {
  231. result = net::ERR_FAILED;
  232. }
  233. }
  234. if (result != net::OK) {
  235. std::move(connect_callback_)
  236. .Run(result, absl::nullopt, absl::nullopt,
  237. mojo::ScopedDataPipeConsumerHandle(),
  238. mojo::ScopedDataPipeProducerHandle());
  239. return;
  240. }
  241. socket_data_pump_ = std::make_unique<SocketDataPump>(
  242. socket_.get(), this /*delegate*/, std::move(receive_producer_handle),
  243. std::move(send_consumer_handle), traffic_annotation_);
  244. std::move(connect_callback_)
  245. .Run(net::OK, local_addr, peer_addr, std::move(receive_consumer_handle),
  246. std::move(send_producer_handle));
  247. }
  248. void TCPConnectedSocket::OnNetworkReadError(int net_error) {
  249. if (observer_)
  250. observer_->OnReadError(net_error);
  251. }
  252. void TCPConnectedSocket::OnNetworkWriteError(int net_error) {
  253. if (observer_)
  254. observer_->OnWriteError(net_error);
  255. }
  256. void TCPConnectedSocket::OnShutdown() {
  257. socket_data_pump_ = nullptr;
  258. if (!pending_upgrade_to_tls_callback_.is_null())
  259. std::move(pending_upgrade_to_tls_callback_).Run();
  260. }
  261. const net::StreamSocket* TCPConnectedSocket::BorrowSocket() {
  262. return socket_.get();
  263. }
  264. std::unique_ptr<net::StreamSocket> TCPConnectedSocket::TakeSocket() {
  265. return std::move(socket_);
  266. }
  267. } // namespace network