PageRenderTime 71ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/net/tools/quic/quic_simple_client.cc

https://gitlab.com/0072016/Facebook-SDK-
C++ | 406 lines | 323 code | 61 blank | 22 comment | 53 complexity | fe397ca6aea5192ac90a2398309c9a76 MD5 | raw file
  1. // Copyright (c) 2012 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 "net/tools/quic/quic_simple_client.h"
  5. #include "base/logging.h"
  6. #include "base/run_loop.h"
  7. #include "base/thread_task_runner_handle.h"
  8. #include "net/base/net_errors.h"
  9. #include "net/http/http_request_info.h"
  10. #include "net/http/http_response_info.h"
  11. #include "net/quic/crypto/quic_random.h"
  12. #include "net/quic/quic_chromium_connection_helper.h"
  13. #include "net/quic/quic_chromium_packet_reader.h"
  14. #include "net/quic/quic_chromium_packet_writer.h"
  15. #include "net/quic/quic_connection.h"
  16. #include "net/quic/quic_flags.h"
  17. #include "net/quic/quic_protocol.h"
  18. #include "net/quic/quic_server_id.h"
  19. #include "net/quic/spdy_utils.h"
  20. #include "net/spdy/spdy_header_block.h"
  21. #include "net/spdy/spdy_http_utils.h"
  22. #include "net/udp/udp_client_socket.h"
  23. using std::string;
  24. using std::vector;
  25. namespace net {
  26. void QuicSimpleClient::ClientQuicDataToResend::Resend() {
  27. client_->SendRequest(*headers_, body_, fin_);
  28. delete headers_;
  29. headers_ = nullptr;
  30. }
  31. QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
  32. const QuicServerId& server_id,
  33. const QuicVersionVector& supported_versions,
  34. ProofVerifier* proof_verifier)
  35. : QuicClientBase(server_id,
  36. supported_versions,
  37. QuicConfig(),
  38. CreateQuicConnectionHelper(),
  39. proof_verifier),
  40. server_address_(server_address),
  41. local_port_(0),
  42. initialized_(false),
  43. packet_reader_started_(false),
  44. weak_factory_(this) {}
  45. QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
  46. const QuicServerId& server_id,
  47. const QuicVersionVector& supported_versions,
  48. const QuicConfig& config,
  49. ProofVerifier* proof_verifier)
  50. : QuicClientBase(server_id,
  51. supported_versions,
  52. config,
  53. CreateQuicConnectionHelper(),
  54. proof_verifier),
  55. server_address_(server_address),
  56. local_port_(0),
  57. initialized_(false),
  58. packet_reader_started_(false),
  59. weak_factory_(this) {}
  60. QuicSimpleClient::~QuicSimpleClient() {
  61. if (connected()) {
  62. session()->connection()->CloseConnection(
  63. QUIC_PEER_GOING_AWAY, "",
  64. ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
  65. }
  66. STLDeleteElements(&data_to_resend_on_connect_);
  67. STLDeleteElements(&data_sent_before_handshake_);
  68. }
  69. bool QuicSimpleClient::Initialize() {
  70. DCHECK(!initialized_);
  71. QuicClientBase::Initialize();
  72. if (!CreateUDPSocket()) {
  73. return false;
  74. }
  75. initialized_ = true;
  76. return true;
  77. }
  78. QuicSimpleClient::QuicDataToResend::QuicDataToResend(HttpRequestInfo* headers,
  79. StringPiece body,
  80. bool fin)
  81. : headers_(headers), body_(body), fin_(fin) {}
  82. QuicSimpleClient::QuicDataToResend::~QuicDataToResend() {
  83. if (headers_) {
  84. delete headers_;
  85. }
  86. }
  87. bool QuicSimpleClient::CreateUDPSocket() {
  88. scoped_ptr<UDPClientSocket> socket(
  89. new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
  90. &net_log_, NetLog::Source()));
  91. int address_family = server_address_.GetSockAddrFamily();
  92. if (bind_to_address_.size() != 0) {
  93. client_address_ = IPEndPoint(bind_to_address_, local_port_);
  94. } else if (address_family == AF_INET) {
  95. client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), local_port_);
  96. } else {
  97. client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), local_port_);
  98. }
  99. int rc = socket->Connect(server_address_);
  100. if (rc != OK) {
  101. LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
  102. return false;
  103. }
  104. rc = socket->SetReceiveBufferSize(kDefaultSocketReceiveBuffer);
  105. if (rc != OK) {
  106. LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc);
  107. return false;
  108. }
  109. rc = socket->SetSendBufferSize(kDefaultSocketReceiveBuffer);
  110. if (rc != OK) {
  111. LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToShortString(rc);
  112. return false;
  113. }
  114. rc = socket->GetLocalAddress(&client_address_);
  115. if (rc != OK) {
  116. LOG(ERROR) << "GetLocalAddress failed: " << ErrorToShortString(rc);
  117. return false;
  118. }
  119. socket_.swap(socket);
  120. packet_reader_.reset(new QuicChromiumPacketReader(
  121. socket_.get(), &clock_, this, kQuicYieldAfterPacketsRead,
  122. QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
  123. BoundNetLog()));
  124. if (socket != nullptr) {
  125. socket->Close();
  126. }
  127. return true;
  128. }
  129. void QuicSimpleClient::StartPacketReaderIfNotStarted() {
  130. if (!packet_reader_started_) {
  131. packet_reader_->StartReading();
  132. packet_reader_started_ = true;
  133. }
  134. }
  135. bool QuicSimpleClient::Connect() {
  136. // Attempt multiple connects until the maximum number of client hellos have
  137. // been sent.
  138. while (!connected() &&
  139. GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
  140. StartConnect();
  141. StartPacketReaderIfNotStarted();
  142. while (EncryptionBeingEstablished()) {
  143. WaitForEvents();
  144. }
  145. if (FLAGS_enable_quic_stateless_reject_support && connected() &&
  146. !data_to_resend_on_connect_.empty()) {
  147. // A connection has been established and there was previously queued data
  148. // to resend. Resend it and empty the queue.
  149. for (QuicDataToResend* data : data_to_resend_on_connect_) {
  150. data->Resend();
  151. }
  152. STLDeleteElements(&data_to_resend_on_connect_);
  153. }
  154. if (session() != nullptr &&
  155. session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
  156. // We've successfully created a session but we're not connected, and there
  157. // is no stateless reject to recover from. Give up trying.
  158. break;
  159. }
  160. }
  161. if (!connected() &&
  162. GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
  163. session() != nullptr &&
  164. session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
  165. // The overall connection failed due too many stateless rejects.
  166. set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
  167. }
  168. return session()->connection()->connected();
  169. }
  170. void QuicSimpleClient::StartConnect() {
  171. DCHECK(initialized_);
  172. DCHECK(!connected());
  173. set_writer(CreateQuicPacketWriter());
  174. if (connected_or_attempting_connect()) {
  175. // Before we destroy the last session and create a new one, gather its stats
  176. // and update the stats for the overall connection.
  177. UpdateStats();
  178. if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
  179. // If the last error was due to a stateless reject, queue up the data to
  180. // be resent on the next successful connection.
  181. // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe
  182. // we should just maintain one queue?
  183. DCHECK(data_to_resend_on_connect_.empty());
  184. data_to_resend_on_connect_.swap(data_sent_before_handshake_);
  185. }
  186. }
  187. CreateQuicClientSession(new QuicConnection(
  188. GetNextConnectionId(), server_address_, helper(), writer(),
  189. /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
  190. session()->Initialize();
  191. session()->CryptoConnect();
  192. set_connected_or_attempting_connect(true);
  193. }
  194. void QuicSimpleClient::Disconnect() {
  195. DCHECK(initialized_);
  196. if (connected()) {
  197. session()->connection()->CloseConnection(
  198. QUIC_PEER_GOING_AWAY, "Client disconnecting",
  199. ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
  200. }
  201. STLDeleteElements(&data_to_resend_on_connect_);
  202. STLDeleteElements(&data_sent_before_handshake_);
  203. reset_writer();
  204. packet_reader_.reset();
  205. initialized_ = false;
  206. }
  207. void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
  208. StringPiece body,
  209. bool fin) {
  210. QuicSpdyClientStream* stream = CreateReliableClientStream();
  211. if (stream == nullptr) {
  212. LOG(DFATAL) << "stream creation failed!";
  213. return;
  214. }
  215. SpdyHeaderBlock header_block;
  216. CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, net::HTTP2,
  217. true, &header_block);
  218. stream->set_visitor(this);
  219. stream->SendRequest(header_block, body, fin);
  220. if (FLAGS_enable_quic_stateless_reject_support) {
  221. // Record this in case we need to resend.
  222. auto new_headers = new HttpRequestInfo;
  223. *new_headers = headers;
  224. auto data_to_resend =
  225. new ClientQuicDataToResend(new_headers, body, fin, this);
  226. MaybeAddQuicDataToResend(data_to_resend);
  227. }
  228. }
  229. void QuicSimpleClient::MaybeAddQuicDataToResend(
  230. QuicDataToResend* data_to_resend) {
  231. DCHECK(FLAGS_enable_quic_stateless_reject_support);
  232. if (session()->IsCryptoHandshakeConfirmed()) {
  233. // The handshake is confirmed. No need to continue saving requests to
  234. // resend.
  235. STLDeleteElements(&data_sent_before_handshake_);
  236. delete data_to_resend;
  237. return;
  238. }
  239. // The handshake is not confirmed. Push the data onto the queue of data to
  240. // resend if statelessly rejected.
  241. data_sent_before_handshake_.push_back(data_to_resend);
  242. }
  243. void QuicSimpleClient::SendRequestAndWaitForResponse(
  244. const HttpRequestInfo& request,
  245. StringPiece body,
  246. bool fin) {
  247. SendRequest(request, body, fin);
  248. while (WaitForEvents()) {
  249. }
  250. }
  251. void QuicSimpleClient::SendRequestsAndWaitForResponse(
  252. const base::CommandLine::StringVector& url_list) {
  253. for (size_t i = 0; i < url_list.size(); ++i) {
  254. HttpRequestInfo request;
  255. request.method = "GET";
  256. request.url = GURL(url_list[i]);
  257. SendRequest(request, "", true);
  258. }
  259. while (WaitForEvents()) {
  260. }
  261. }
  262. bool QuicSimpleClient::WaitForEvents() {
  263. DCHECK(connected());
  264. base::RunLoop().RunUntilIdle();
  265. DCHECK(session() != nullptr);
  266. if (!connected() &&
  267. session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
  268. DCHECK(FLAGS_enable_quic_stateless_reject_support);
  269. DVLOG(1) << "Detected stateless reject while waiting for events. "
  270. << "Attempting to reconnect.";
  271. Connect();
  272. }
  273. return session()->num_active_requests() != 0;
  274. }
  275. bool QuicSimpleClient::MigrateSocket(const IPAddress& new_host) {
  276. if (!connected()) {
  277. return false;
  278. }
  279. bind_to_address_ = new_host;
  280. if (!CreateUDPSocket()) {
  281. return false;
  282. }
  283. session()->connection()->SetSelfAddress(client_address_);
  284. QuicPacketWriter* writer = CreateQuicPacketWriter();
  285. set_writer(writer);
  286. session()->connection()->SetQuicPacketWriter(writer, false);
  287. return true;
  288. }
  289. void QuicSimpleClient::OnClose(QuicSpdyStream* stream) {
  290. DCHECK(stream != nullptr);
  291. QuicSpdyClientStream* client_stream =
  292. static_cast<QuicSpdyClientStream*>(stream);
  293. HttpResponseInfo response;
  294. SpdyHeadersToHttpResponse(client_stream->response_headers(), net::HTTP2,
  295. &response);
  296. if (response_listener_.get() != nullptr) {
  297. response_listener_->OnCompleteResponse(stream->id(), *response.headers,
  298. client_stream->data());
  299. }
  300. // Store response headers and body.
  301. if (store_response_) {
  302. latest_response_code_ = client_stream->response_code();
  303. response.headers->GetNormalizedHeaders(&latest_response_headers_);
  304. latest_response_body_ = client_stream->data();
  305. }
  306. }
  307. size_t QuicSimpleClient::latest_response_code() const {
  308. LOG_IF(DFATAL, !store_response_) << "Response not stored!";
  309. return latest_response_code_;
  310. }
  311. const string& QuicSimpleClient::latest_response_headers() const {
  312. LOG_IF(DFATAL, !store_response_) << "Response not stored!";
  313. return latest_response_headers_;
  314. }
  315. const string& QuicSimpleClient::latest_response_body() const {
  316. LOG_IF(DFATAL, !store_response_) << "Response not stored!";
  317. return latest_response_body_;
  318. }
  319. QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() {
  320. return helper()->GetRandomGenerator()->RandUint64();
  321. }
  322. QuicChromiumConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
  323. return new QuicChromiumConnectionHelper(
  324. base::ThreadTaskRunnerHandle::Get().get(), &clock_,
  325. QuicRandom::GetInstance());
  326. }
  327. QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() {
  328. return new QuicChromiumPacketWriter(socket_.get());
  329. }
  330. void QuicSimpleClient::OnReadError(int result,
  331. const DatagramClientSocket* socket) {
  332. LOG(ERROR) << "QuicSimpleClient read failed: " << ErrorToShortString(result);
  333. Disconnect();
  334. }
  335. bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
  336. IPEndPoint local_address,
  337. IPEndPoint peer_address) {
  338. session()->connection()->ProcessUdpPacket(local_address, peer_address,
  339. packet);
  340. if (!session()->connection()->connected()) {
  341. return false;
  342. }
  343. return true;
  344. }
  345. } // namespace net