Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
bloba477336f7b858a77ebe2cd974fa217b4101fef15
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 : QuicClient(server_address,
45 server_id,
46 supported_versions,
47 QuicConfig(),
48 epoll_server) {}
50 QuicClient::QuicClient(IPEndPoint server_address,
51 const QuicServerId& server_id,
52 const QuicVersionVector& supported_versions,
53 const QuicConfig& config,
54 EpollServer* epoll_server)
55 : server_address_(server_address),
56 server_id_(server_id),
57 config_(config),
58 local_port_(0),
59 epoll_server_(epoll_server),
60 fd_(-1),
61 helper_(CreateQuicConnectionHelper()),
62 initialized_(false),
63 packets_dropped_(0),
64 overflow_supported_(false),
65 supported_versions_(supported_versions),
66 store_response_(false),
67 latest_response_code_(-1),
68 initial_max_packet_length_(0) {}
70 QuicClient::~QuicClient() {
71 if (connected()) {
72 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
75 CleanUpUDPSocketImpl();
78 bool QuicClient::Initialize() {
79 DCHECK(!initialized_);
81 // If an initial flow control window has not explicitly been set, then use the
82 // same values that Chrome uses.
83 const uint32 kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
84 const uint32 kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
85 if (config_.GetInitialStreamFlowControlWindowToSend() ==
86 kMinimumFlowControlSendWindow) {
87 config_.SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
89 if (config_.GetInitialSessionFlowControlWindowToSend() ==
90 kMinimumFlowControlSendWindow) {
91 config_.SetInitialSessionFlowControlWindowToSend(kSessionMaxRecvWindowSize);
94 epoll_server_->set_timeout_in_us(50 * 1000);
96 if (!CreateUDPSocket()) {
97 return false;
100 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
101 initialized_ = true;
102 return true;
105 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
106 QuicPacketWriter* writer)
107 : writer_(writer) {}
109 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
111 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
112 QuicConnection* /*connection*/) const {
113 return writer_;
117 bool QuicClient::CreateUDPSocket() {
118 int address_family = server_address_.GetSockAddrFamily();
119 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
120 if (fd_ < 0) {
121 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
122 return false;
125 int get_overflow = 1;
126 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
127 sizeof(get_overflow));
128 if (rc < 0) {
129 DLOG(WARNING) << "Socket overflow detection not supported";
130 } else {
131 overflow_supported_ = true;
134 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
135 kDefaultSocketReceiveBuffer)) {
136 return false;
139 if (!QuicSocketUtils::SetSendBufferSize(fd_, kDefaultSocketReceiveBuffer)) {
140 return false;
143 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
144 if (rc < 0) {
145 LOG(ERROR) << "IP detection not supported" << strerror(errno);
146 return false;
149 if (bind_to_address_.size() != 0) {
150 client_address_ = IPEndPoint(bind_to_address_, local_port_);
151 } else if (address_family == AF_INET) {
152 IPAddressNumber any4;
153 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
154 client_address_ = IPEndPoint(any4, local_port_);
155 } else {
156 IPAddressNumber any6;
157 CHECK(net::ParseIPLiteralToNumber("::", &any6));
158 client_address_ = IPEndPoint(any6, local_port_);
161 sockaddr_storage raw_addr;
162 socklen_t raw_addr_len = sizeof(raw_addr);
163 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
164 &raw_addr_len));
165 rc = bind(fd_,
166 reinterpret_cast<const sockaddr*>(&raw_addr),
167 sizeof(raw_addr));
168 if (rc < 0) {
169 LOG(ERROR) << "Bind failed: " << strerror(errno);
170 return false;
173 SockaddrStorage storage;
174 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
175 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
176 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
179 return true;
182 bool QuicClient::Connect() {
183 StartConnect();
184 while (EncryptionBeingEstablished()) {
185 WaitForEvents();
187 return session_->connection()->connected();
190 QuicClientSession* QuicClient::CreateQuicClientSession(
191 const QuicConfig& config,
192 QuicConnection* connection,
193 const QuicServerId& server_id,
194 QuicCryptoClientConfig* crypto_config) {
195 return new QuicClientSession(config, connection, server_id_, &crypto_config_);
198 void QuicClient::StartConnect() {
199 DCHECK(initialized_);
200 DCHECK(!connected());
202 QuicPacketWriter* writer = CreateQuicPacketWriter();
204 DummyPacketWriterFactory factory(writer);
206 session_.reset(CreateQuicClientSession(
207 config_,
208 new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
209 factory,
210 /* owns_writer= */ false, Perspective::IS_CLIENT,
211 server_id_.is_https(), supported_versions_),
212 server_id_, &crypto_config_));
213 if (initial_max_packet_length_ != 0) {
214 session_->connection()->set_max_packet_length(initial_max_packet_length_);
217 // Reset |writer_| after |session_| so that the old writer outlives the old
218 // session.
219 if (writer_.get() != writer) {
220 writer_.reset(writer);
222 session_->Initialize();
223 session_->CryptoConnect();
226 bool QuicClient::EncryptionBeingEstablished() {
227 return !session_->IsEncryptionEstablished() &&
228 session_->connection()->connected();
231 void QuicClient::Disconnect() {
232 DCHECK(initialized_);
234 if (connected()) {
235 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
238 CleanUpUDPSocket();
240 initialized_ = false;
243 void QuicClient::CleanUpUDPSocket() {
244 CleanUpUDPSocketImpl();
247 void QuicClient::CleanUpUDPSocketImpl() {
248 if (fd_ > -1) {
249 epoll_server_->UnregisterFD(fd_);
250 int rc = close(fd_);
251 DCHECK_EQ(0, rc);
252 fd_ = -1;
256 void QuicClient::SendRequest(const BalsaHeaders& headers,
257 StringPiece body,
258 bool fin) {
259 QuicSpdyClientStream* stream = CreateReliableClientStream();
260 if (stream == nullptr) {
261 LOG(DFATAL) << "stream creation failed!";
262 return;
264 stream->SendRequest(
265 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers, stream->version()),
266 body, fin);
267 stream->set_visitor(this);
270 void QuicClient::SendRequestAndWaitForResponse(
271 const BalsaHeaders& headers,
272 StringPiece body,
273 bool fin) {
274 SendRequest(headers, body, fin);
275 while (WaitForEvents()) {}
278 void QuicClient::SendRequestsAndWaitForResponse(
279 const vector<string>& url_list) {
280 for (size_t i = 0; i < url_list.size(); ++i) {
281 BalsaHeaders headers;
282 headers.SetRequestFirstlineFromStringPieces("GET", url_list[i], "HTTP/1.1");
283 SendRequest(headers, "", true);
285 while (WaitForEvents()) {}
288 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
289 if (!connected()) {
290 return nullptr;
293 return session_->CreateOutgoingDynamicStream();
296 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
297 DCHECK(connected());
299 while (connected() && !session_->IsClosedStream(id)) {
300 WaitForEvents();
304 void QuicClient::WaitForCryptoHandshakeConfirmed() {
305 DCHECK(connected());
307 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
308 WaitForEvents();
312 bool QuicClient::WaitForEvents() {
313 DCHECK(connected());
315 epoll_server_->WaitForEventsAndExecuteCallbacks();
316 return session_->num_active_requests() != 0;
319 bool QuicClient::MigrateSocket(const IPAddressNumber& new_host) {
320 if (!connected()) {
321 return false;
324 CleanUpUDPSocket();
326 bind_to_address_ = new_host;
327 if (!CreateUDPSocket()) {
328 return false;
331 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
332 session_->connection()->SetSelfAddress(client_address_);
334 QuicPacketWriter* writer = CreateQuicPacketWriter();
335 DummyPacketWriterFactory factory(writer);
336 if (writer_.get() != writer) {
337 writer_.reset(writer);
339 session_->connection()->SetQuicPacketWriter(writer, false);
341 return true;
344 void QuicClient::OnEvent(int fd, EpollEvent* event) {
345 DCHECK_EQ(fd, fd_);
347 if (event->in_events & EPOLLIN) {
348 while (connected() && ReadAndProcessPacket()) {
351 if (connected() && (event->in_events & EPOLLOUT)) {
352 writer_->SetWritable();
353 session_->connection()->OnCanWrite();
355 if (event->in_events & EPOLLERR) {
356 DVLOG(1) << "Epollerr";
360 void QuicClient::OnClose(QuicDataStream* stream) {
361 QuicSpdyClientStream* client_stream =
362 static_cast<QuicSpdyClientStream*>(stream);
363 BalsaHeaders headers;
364 SpdyBalsaUtils::SpdyHeadersToResponseHeaders(client_stream->headers(),
365 &headers, stream->version());
367 if (response_listener_.get() != nullptr) {
368 response_listener_->OnCompleteResponse(
369 stream->id(), headers, client_stream->data());
372 // Store response headers and body.
373 if (store_response_) {
374 latest_response_code_ = headers.parsed_response_code();
375 headers.DumpHeadersToString(&latest_response_headers_);
376 latest_response_body_ = client_stream->data();
380 bool QuicClient::connected() const {
381 return session_.get() && session_->connection() &&
382 session_->connection()->connected();
385 bool QuicClient::goaway_received() const {
386 return session_ != nullptr && session_->goaway_received();
389 size_t QuicClient::latest_response_code() const {
390 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
391 return latest_response_code_;
394 const string& QuicClient::latest_response_headers() const {
395 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
396 return latest_response_headers_;
399 const string& QuicClient::latest_response_body() const {
400 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
401 return latest_response_body_;
404 QuicConnectionId QuicClient::GenerateConnectionId() {
405 return QuicRandom::GetInstance()->RandUint64();
408 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
409 return new QuicEpollConnectionHelper(epoll_server_);
412 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
413 return new QuicDefaultPacketWriter(fd_);
416 int QuicClient::ReadPacket(char* buffer,
417 int buffer_len,
418 IPEndPoint* server_address,
419 IPAddressNumber* client_ip) {
420 return QuicSocketUtils::ReadPacket(
421 fd_, buffer, buffer_len,
422 overflow_supported_ ? &packets_dropped_ : nullptr, client_ip,
423 server_address);
426 bool QuicClient::ReadAndProcessPacket() {
427 // Allocate some extra space so we can send an error if the server goes over
428 // the limit.
429 char buf[2 * kMaxPacketSize];
431 IPEndPoint server_address;
432 IPAddressNumber client_ip;
434 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
436 if (bytes_read < 0) {
437 return false;
440 QuicEncryptedPacket packet(buf, bytes_read, false);
442 IPEndPoint client_address(client_ip, client_address_.port());
443 session_->connection()->ProcessUdpPacket(
444 client_address, server_address, packet);
445 return true;
448 } // namespace tools
449 } // namespace net