[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blob24ce0007cfe428405af18d965baff928add39841
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_client.h"
7 #include <errno.h>
8 #include <netinet/in.h>
9 #include <string.h>
10 #include <sys/epoll.h>
11 #include <sys/socket.h>
12 #include <unistd.h>
14 #include "base/logging.h"
15 #include "net/base/net_util.h"
16 #include "net/quic/crypto/quic_random.h"
17 #include "net/quic/quic_connection.h"
18 #include "net/quic/quic_data_reader.h"
19 #include "net/quic/quic_protocol.h"
20 #include "net/quic/quic_server_id.h"
21 #include "net/tools/balsa/balsa_headers.h"
22 #include "net/tools/epoll_server/epoll_server.h"
23 #include "net/tools/quic/quic_epoll_connection_helper.h"
24 #include "net/tools/quic/quic_socket_utils.h"
25 #include "net/tools/quic/quic_spdy_client_stream.h"
26 #include "net/tools/quic/spdy_balsa_utils.h"
28 #ifndef SO_RXQ_OVFL
29 #define SO_RXQ_OVFL 40
30 #endif
32 using std::string;
33 using std::vector;
35 namespace net {
36 namespace tools {
38 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
40 QuicClient::QuicClient(IPEndPoint server_address,
41 const QuicServerId& server_id,
42 const QuicVersionVector& supported_versions,
43 EpollServer* epoll_server)
44 : server_address_(server_address),
45 server_id_(server_id),
46 local_port_(0),
47 epoll_server_(epoll_server),
48 fd_(-1),
49 helper_(CreateQuicConnectionHelper()),
50 initialized_(false),
51 packets_dropped_(0),
52 overflow_supported_(false),
53 supported_versions_(supported_versions),
54 store_response_(false),
55 latest_response_code_(-1) {
58 QuicClient::QuicClient(IPEndPoint server_address,
59 const QuicServerId& server_id,
60 const QuicVersionVector& supported_versions,
61 const QuicConfig& config,
62 EpollServer* epoll_server)
63 : server_address_(server_address),
64 server_id_(server_id),
65 config_(config),
66 local_port_(0),
67 epoll_server_(epoll_server),
68 fd_(-1),
69 helper_(CreateQuicConnectionHelper()),
70 initialized_(false),
71 packets_dropped_(0),
72 overflow_supported_(false),
73 supported_versions_(supported_versions),
74 store_response_(false),
75 latest_response_code_(-1) {
78 QuicClient::~QuicClient() {
79 if (connected()) {
80 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
83 CleanUpUDPSocketImpl();
86 bool QuicClient::Initialize() {
87 DCHECK(!initialized_);
89 // If an initial flow control window has not explicitly been set, then use the
90 // same values that Chrome uses.
91 const uint32 kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
92 const uint32 kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
93 if (config_.GetInitialStreamFlowControlWindowToSend() ==
94 kMinimumFlowControlSendWindow) {
95 config_.SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
97 if (config_.GetInitialSessionFlowControlWindowToSend() ==
98 kMinimumFlowControlSendWindow) {
99 config_.SetInitialSessionFlowControlWindowToSend(kSessionMaxRecvWindowSize);
102 epoll_server_->set_timeout_in_us(50 * 1000);
104 if (!CreateUDPSocket()) {
105 return false;
108 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
109 initialized_ = true;
110 return true;
113 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
114 QuicPacketWriter* writer)
115 : writer_(writer) {}
117 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
119 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
120 QuicConnection* /*connection*/) const {
121 return writer_;
125 bool QuicClient::CreateUDPSocket() {
126 int address_family = server_address_.GetSockAddrFamily();
127 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
128 if (fd_ < 0) {
129 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
130 return false;
133 int get_overflow = 1;
134 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
135 sizeof(get_overflow));
136 if (rc < 0) {
137 DLOG(WARNING) << "Socket overflow detection not supported";
138 } else {
139 overflow_supported_ = true;
142 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
143 kDefaultSocketReceiveBuffer)) {
144 return false;
147 if (!QuicSocketUtils::SetSendBufferSize(fd_, kDefaultSocketReceiveBuffer)) {
148 return false;
151 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
152 if (rc < 0) {
153 LOG(ERROR) << "IP detection not supported" << strerror(errno);
154 return false;
157 if (bind_to_address_.size() != 0) {
158 client_address_ = IPEndPoint(bind_to_address_, local_port_);
159 } else if (address_family == AF_INET) {
160 IPAddressNumber any4;
161 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
162 client_address_ = IPEndPoint(any4, local_port_);
163 } else {
164 IPAddressNumber any6;
165 CHECK(net::ParseIPLiteralToNumber("::", &any6));
166 client_address_ = IPEndPoint(any6, local_port_);
169 sockaddr_storage raw_addr;
170 socklen_t raw_addr_len = sizeof(raw_addr);
171 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
172 &raw_addr_len));
173 rc = bind(fd_,
174 reinterpret_cast<const sockaddr*>(&raw_addr),
175 sizeof(raw_addr));
176 if (rc < 0) {
177 LOG(ERROR) << "Bind failed: " << strerror(errno);
178 return false;
181 SockaddrStorage storage;
182 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
183 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
184 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
187 return true;
190 bool QuicClient::Connect() {
191 StartConnect();
192 while (EncryptionBeingEstablished()) {
193 WaitForEvents();
195 return session_->connection()->connected();
198 QuicClientSession* QuicClient::CreateQuicClientSession(
199 const QuicConfig& config,
200 QuicConnection* connection,
201 const QuicServerId& server_id,
202 QuicCryptoClientConfig* crypto_config) {
203 return new QuicClientSession(config, connection, server_id_, &crypto_config_);
206 void QuicClient::StartConnect() {
207 DCHECK(initialized_);
208 DCHECK(!connected());
210 QuicPacketWriter* writer = CreateQuicPacketWriter();
212 DummyPacketWriterFactory factory(writer);
214 session_.reset(CreateQuicClientSession(
215 config_,
216 new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
217 factory,
218 /* owns_writer= */ false, Perspective::IS_CLIENT,
219 server_id_.is_https(), supported_versions_),
220 server_id_, &crypto_config_));
222 // Reset |writer_| after |session_| so that the old writer outlives the old
223 // session.
224 if (writer_.get() != writer) {
225 writer_.reset(writer);
227 session_->Initialize();
228 session_->CryptoConnect();
231 bool QuicClient::EncryptionBeingEstablished() {
232 return !session_->IsEncryptionEstablished() &&
233 session_->connection()->connected();
236 void QuicClient::Disconnect() {
237 DCHECK(initialized_);
239 if (connected()) {
240 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
243 CleanUpUDPSocket();
245 initialized_ = false;
248 void QuicClient::CleanUpUDPSocket() {
249 CleanUpUDPSocketImpl();
252 void QuicClient::CleanUpUDPSocketImpl() {
253 if (fd_ > -1) {
254 epoll_server_->UnregisterFD(fd_);
255 int rc = close(fd_);
256 DCHECK_EQ(0, rc);
257 fd_ = -1;
261 void QuicClient::SendRequest(const BalsaHeaders& headers,
262 StringPiece body,
263 bool fin) {
264 QuicSpdyClientStream* stream = CreateReliableClientStream();
265 if (stream == nullptr) {
266 LOG(DFATAL) << "stream creation failed!";
267 return;
269 stream->SendRequest(
270 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers, stream->version()),
271 body, fin);
272 stream->set_visitor(this);
275 void QuicClient::SendRequestAndWaitForResponse(
276 const BalsaHeaders& headers,
277 StringPiece body,
278 bool fin) {
279 SendRequest(headers, body, fin);
280 while (WaitForEvents()) {}
283 void QuicClient::SendRequestsAndWaitForResponse(
284 const vector<string>& url_list) {
285 for (size_t i = 0; i < url_list.size(); ++i) {
286 BalsaHeaders headers;
287 headers.SetRequestFirstlineFromStringPieces("GET", url_list[i], "HTTP/1.1");
288 SendRequest(headers, "", true);
290 while (WaitForEvents()) {}
293 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
294 if (!connected()) {
295 return nullptr;
298 return session_->CreateOutgoingDataStream();
301 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
302 DCHECK(connected());
304 while (connected() && !session_->IsClosedStream(id)) {
305 WaitForEvents();
309 void QuicClient::WaitForCryptoHandshakeConfirmed() {
310 DCHECK(connected());
312 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
313 WaitForEvents();
317 bool QuicClient::WaitForEvents() {
318 DCHECK(connected());
320 epoll_server_->WaitForEventsAndExecuteCallbacks();
321 return session_->num_active_requests() != 0;
324 void QuicClient::OnEvent(int fd, EpollEvent* event) {
325 DCHECK_EQ(fd, fd_);
327 if (event->in_events & EPOLLIN) {
328 while (connected() && ReadAndProcessPacket()) {
331 if (connected() && (event->in_events & EPOLLOUT)) {
332 writer_->SetWritable();
333 session_->connection()->OnCanWrite();
335 if (event->in_events & EPOLLERR) {
336 DVLOG(1) << "Epollerr";
340 void QuicClient::OnClose(QuicDataStream* stream) {
341 QuicSpdyClientStream* client_stream =
342 static_cast<QuicSpdyClientStream*>(stream);
343 BalsaHeaders headers;
344 SpdyBalsaUtils::SpdyHeadersToResponseHeaders(client_stream->headers(),
345 &headers, stream->version());
347 if (response_listener_.get() != nullptr) {
348 response_listener_->OnCompleteResponse(
349 stream->id(), headers, client_stream->data());
352 // Store response headers and body.
353 if (store_response_) {
354 latest_response_code_ = headers.parsed_response_code();
355 headers.DumpHeadersToString(&latest_response_headers_);
356 latest_response_body_ = client_stream->data();
360 bool QuicClient::connected() const {
361 return session_.get() && session_->connection() &&
362 session_->connection()->connected();
365 bool QuicClient::goaway_received() const {
366 return session_ != nullptr && session_->goaway_received();
369 size_t QuicClient::latest_response_code() const {
370 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
371 return latest_response_code_;
374 const string& QuicClient::latest_response_headers() const {
375 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
376 return latest_response_headers_;
379 const string& QuicClient::latest_response_body() const {
380 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
381 return latest_response_body_;
384 QuicConnectionId QuicClient::GenerateConnectionId() {
385 return QuicRandom::GetInstance()->RandUint64();
388 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
389 return new QuicEpollConnectionHelper(epoll_server_);
392 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
393 return new QuicDefaultPacketWriter(fd_);
396 int QuicClient::ReadPacket(char* buffer,
397 int buffer_len,
398 IPEndPoint* server_address,
399 IPAddressNumber* client_ip) {
400 return QuicSocketUtils::ReadPacket(
401 fd_, buffer, buffer_len,
402 overflow_supported_ ? &packets_dropped_ : nullptr, client_ip,
403 server_address);
406 bool QuicClient::ReadAndProcessPacket() {
407 // Allocate some extra space so we can send an error if the server goes over
408 // the limit.
409 char buf[2 * kMaxPacketSize];
411 IPEndPoint server_address;
412 IPAddressNumber client_ip;
414 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
416 if (bytes_read < 0) {
417 return false;
420 QuicEncryptedPacket packet(buf, bytes_read, false);
422 IPEndPoint client_address(client_ip, client_address_.port());
423 session_->connection()->ProcessUdpPacket(
424 client_address, server_address, packet);
425 return true;
428 } // namespace tools
429 } // namespace net