Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / tools / quic / quic_simple_client.cc
blobd23893b68809330880bf1e17fb3c89383c1c1e27
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.
5 #include "net/tools/quic/quic_simple_client.h"
7 #include "base/logging.h"
8 #include "base/run_loop.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "net/base/net_errors.h"
11 #include "net/http/http_request_info.h"
12 #include "net/http/http_response_info.h"
13 #include "net/quic/crypto/quic_random.h"
14 #include "net/quic/quic_connection.h"
15 #include "net/quic/quic_connection_helper.h"
16 #include "net/quic/quic_default_packet_writer.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_http_utils.h"
21 #include "net/udp/udp_client_socket.h"
23 using std::string;
24 using std::vector;
26 namespace net {
27 namespace tools {
29 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
30 const QuicServerId& server_id,
31 const QuicVersionVector& supported_versions)
32 : server_address_(server_address),
33 server_id_(server_id),
34 local_port_(0),
35 helper_(CreateQuicConnectionHelper()),
36 initialized_(false),
37 supported_versions_(supported_versions),
38 weak_factory_(this) {
41 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
42 const QuicServerId& server_id,
43 const QuicVersionVector& supported_versions,
44 const QuicConfig& config)
45 : server_address_(server_address),
46 server_id_(server_id),
47 config_(config),
48 local_port_(0),
49 helper_(CreateQuicConnectionHelper()),
50 initialized_(false),
51 supported_versions_(supported_versions),
52 initial_max_packet_length_(0),
53 weak_factory_(this) {}
55 QuicSimpleClient::~QuicSimpleClient() {
56 if (connected()) {
57 session()->connection()->SendConnectionClosePacket(
58 QUIC_PEER_GOING_AWAY, "");
62 bool QuicSimpleClient::Initialize() {
63 DCHECK(!initialized_);
65 if (!CreateUDPSocket()) {
66 return false;
69 initialized_ = true;
70 return true;
73 QuicSimpleClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
74 QuicPacketWriter* writer)
75 : writer_(writer) {}
77 QuicSimpleClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
79 QuicPacketWriter* QuicSimpleClient::DummyPacketWriterFactory::Create(
80 QuicConnection* /*connection*/) const {
81 return writer_;
84 bool QuicSimpleClient::CreateUDPSocket() {
85 scoped_ptr<UDPClientSocket> socket(
86 new UDPClientSocket(DatagramSocket::DEFAULT_BIND,
87 RandIntCallback(),
88 &net_log_,
89 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 IPAddressNumber any4;
96 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
97 client_address_ = IPEndPoint(any4, local_port_);
98 } else {
99 IPAddressNumber any6;
100 CHECK(net::ParseIPLiteralToNumber("::", &any6));
101 client_address_ = IPEndPoint(any6, local_port_);
104 int rc = socket->Connect(server_address_);
105 if (rc != OK) {
106 LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
107 return false;
110 rc = socket->SetReceiveBufferSize(kDefaultSocketReceiveBuffer);
111 if (rc != OK) {
112 LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc);
113 return false;
116 rc = socket->SetSendBufferSize(kDefaultSocketReceiveBuffer);
117 if (rc != OK) {
118 LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToShortString(rc);
119 return false;
122 rc = socket->GetLocalAddress(&client_address_);
123 if (rc != OK) {
124 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToShortString(rc);
125 return false;
128 socket_.swap(socket);
129 packet_reader_.reset(new QuicPacketReader(socket_.get(), this,
130 BoundNetLog()));
132 if (socket != nullptr) {
133 socket->Close();
136 return true;
139 bool QuicSimpleClient::Connect() {
140 StartConnect();
141 packet_reader_->StartReading();
142 while (EncryptionBeingEstablished()) {
143 WaitForEvents();
145 return session_->connection()->connected();
148 QuicClientSession* QuicSimpleClient::CreateQuicClientSession(
149 const QuicConfig& config,
150 QuicConnection* connection,
151 const QuicServerId& server_id,
152 QuicCryptoClientConfig* crypto_config) {
153 return new QuicClientSession(config, connection, server_id_, &crypto_config_);
156 void QuicSimpleClient::StartConnect() {
157 DCHECK(initialized_);
158 DCHECK(!connected());
160 writer_.reset(CreateQuicPacketWriter());
161 connection_ = new QuicConnection(GenerateConnectionId(),
162 server_address_,
163 helper_.get(),
164 DummyPacketWriterFactory(writer_.get()),
165 /* owns_writer= */ false,
166 Perspective::IS_CLIENT,
167 server_id_.is_https(),
168 supported_versions_);
169 session_.reset(CreateQuicClientSession(config_, connection_, server_id_,
170 &crypto_config_));
171 if (initial_max_packet_length_ != 0) {
172 session_->connection()->set_max_packet_length(initial_max_packet_length_);
174 session_->Initialize();
175 session_->CryptoConnect();
178 bool QuicSimpleClient::EncryptionBeingEstablished() {
179 return !session_->IsEncryptionEstablished() &&
180 session_->connection()->connected();
183 void QuicSimpleClient::Disconnect() {
184 DCHECK(initialized_);
186 if (connected()) {
187 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
190 writer_.reset();
191 packet_reader_.reset();
193 initialized_ = false;
196 void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
197 base::StringPiece body,
198 bool fin) {
199 QuicSpdyClientStream* stream = CreateReliableClientStream();
200 if (stream == nullptr) {
201 LOG(DFATAL) << "stream creation failed!";
202 return;
204 SpdyHeaderBlock header_block;
205 SpdyMajorVersion spdy_version =
206 SpdyUtils::GetSpdyVersionForQuicVersion(stream->version());
207 CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, spdy_version,
208 true, &header_block);
209 stream->SendRequest(header_block, body, fin);
210 stream->set_visitor(this);
213 void QuicSimpleClient::SendRequestAndWaitForResponse(
214 const HttpRequestInfo& request,
215 base::StringPiece body,
216 bool fin) {
217 SendRequest(request, body, fin);
218 while (WaitForEvents()) {}
221 void QuicSimpleClient::SendRequestsAndWaitForResponse(
222 const base::CommandLine::StringVector& url_list) {
223 for (size_t i = 0; i < url_list.size(); ++i) {
224 HttpRequestInfo request;
225 request.method = "GET";
226 request.url = GURL(url_list[i]);
227 SendRequest(request, "", true);
230 while (WaitForEvents()) {}
233 QuicSpdyClientStream* QuicSimpleClient::CreateReliableClientStream() {
234 if (!connected()) {
235 return nullptr;
238 return session_->CreateOutgoingDynamicStream();
241 void QuicSimpleClient::WaitForStreamToClose(QuicStreamId id) {
242 DCHECK(connected());
244 while (connected() && !session_->IsClosedStream(id)) {
245 WaitForEvents();
249 void QuicSimpleClient::WaitForCryptoHandshakeConfirmed() {
250 DCHECK(connected());
252 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
253 WaitForEvents();
257 bool QuicSimpleClient::WaitForEvents() {
258 DCHECK(connected());
260 base::RunLoop().RunUntilIdle();
261 return session_->num_active_requests() != 0;
264 bool QuicSimpleClient::MigrateSocket(const IPAddressNumber& new_host) {
265 if (!connected()) {
266 return false;
269 bind_to_address_ = new_host;
270 if (!CreateUDPSocket()) {
271 return false;
274 session_->connection()->SetSelfAddress(client_address_);
276 QuicPacketWriter* writer = CreateQuicPacketWriter();
277 DummyPacketWriterFactory factory(writer);
278 if (writer_.get() != writer) {
279 writer_.reset(writer);
281 session_->connection()->SetQuicPacketWriter(writer, false);
283 return true;
286 void QuicSimpleClient::OnClose(QuicDataStream* stream) {
287 QuicSpdyClientStream* client_stream =
288 static_cast<QuicSpdyClientStream*>(stream);
289 HttpResponseInfo response;
290 SpdyMajorVersion spdy_version =
291 SpdyUtils::GetSpdyVersionForQuicVersion(client_stream->version());
292 SpdyHeadersToHttpResponse(client_stream->headers(), spdy_version, &response);
293 if (response_listener_.get() != nullptr) {
294 response_listener_->OnCompleteResponse(
295 stream->id(), *response.headers, client_stream->data());
298 // Store response headers and body.
299 if (store_response_) {
300 latest_response_code_ = client_stream->response_code();
301 response.headers->GetNormalizedHeaders(&latest_response_headers_);
302 latest_response_body_ = client_stream->data();
306 bool QuicSimpleClient::connected() const {
307 return session_.get() && session_->connection() &&
308 session_->connection()->connected();
311 bool QuicSimpleClient::goaway_received() const {
312 return session_ != nullptr && session_->goaway_received();
315 size_t QuicSimpleClient::latest_response_code() const {
316 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
317 return latest_response_code_;
320 const string& QuicSimpleClient::latest_response_headers() const {
321 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
322 return latest_response_headers_;
325 const string& QuicSimpleClient::latest_response_body() const {
326 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
327 return latest_response_body_;
330 QuicConnectionId QuicSimpleClient::GenerateConnectionId() {
331 return helper_->GetRandomGenerator()->RandUint64();
334 QuicConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
335 return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
336 &clock_, QuicRandom::GetInstance());
339 QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() {
340 return new QuicDefaultPacketWriter(socket_.get());
343 void QuicSimpleClient::OnReadError(int result) {
344 LOG(ERROR) << "QuicSimpleClient read failed: " << ErrorToShortString(result);
345 Disconnect();
348 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet,
349 IPEndPoint local_address,
350 IPEndPoint peer_address) {
351 session_->connection()->ProcessUdpPacket(local_address, peer_address, packet);
352 if (!session_->connection()->connected()) {
353 return false;
356 return true;
359 } // namespace tools
360 } // namespace net