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"
8 #include <netinet/in.h>
10 #include <sys/epoll.h>
11 #include <sys/socket.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"
29 #define SO_RXQ_OVFL 40
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
,
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
),
59 epoll_server_(epoll_server
),
61 helper_(CreateQuicConnectionHelper()),
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() {
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()) {
100 epoll_server_
->RegisterFD(fd_
, this, kEpollFlags
);
105 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
106 QuicPacketWriter
* writer
)
109 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
111 QuicPacketWriter
* QuicClient::DummyPacketWriterFactory::Create(
112 QuicConnection
* /*connection*/) const {
117 bool QuicClient::CreateUDPSocket() {
118 int address_family
= server_address_
.GetSockAddrFamily();
119 fd_
= socket(address_family
, SOCK_DGRAM
| SOCK_NONBLOCK
, IPPROTO_UDP
);
121 LOG(ERROR
) << "CreateSocket() failed: " << strerror(errno
);
125 int get_overflow
= 1;
126 int rc
= setsockopt(fd_
, SOL_SOCKET
, SO_RXQ_OVFL
, &get_overflow
,
127 sizeof(get_overflow
));
129 DLOG(WARNING
) << "Socket overflow detection not supported";
131 overflow_supported_
= true;
134 if (!QuicSocketUtils::SetReceiveBufferSize(fd_
,
135 kDefaultSocketReceiveBuffer
)) {
139 if (!QuicSocketUtils::SetSendBufferSize(fd_
, kDefaultSocketReceiveBuffer
)) {
143 rc
= QuicSocketUtils::SetGetAddressInfo(fd_
, address_family
);
145 LOG(ERROR
) << "IP detection not supported" << strerror(errno
);
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_
);
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
),
166 reinterpret_cast<const sockaddr
*>(&raw_addr
),
169 LOG(ERROR
) << "Bind failed: " << strerror(errno
);
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
);
182 bool QuicClient::Connect() {
184 while (EncryptionBeingEstablished()) {
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(
208 new QuicConnection(GenerateConnectionId(), server_address_
, helper_
.get(),
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
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_
);
235 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
240 initialized_
= false;
243 void QuicClient::CleanUpUDPSocket() {
244 CleanUpUDPSocketImpl();
247 void QuicClient::CleanUpUDPSocketImpl() {
249 epoll_server_
->UnregisterFD(fd_
);
256 void QuicClient::SendRequest(const BalsaHeaders
& headers
,
259 QuicSpdyClientStream
* stream
= CreateReliableClientStream();
260 if (stream
== nullptr) {
261 LOG(DFATAL
) << "stream creation failed!";
265 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers
, stream
->version()),
267 stream
->set_visitor(this);
270 void QuicClient::SendRequestAndWaitForResponse(
271 const BalsaHeaders
& headers
,
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() {
293 return session_
->CreateOutgoingDynamicStream();
296 void QuicClient::WaitForStreamToClose(QuicStreamId id
) {
299 while (connected() && !session_
->IsClosedStream(id
)) {
304 void QuicClient::WaitForCryptoHandshakeConfirmed() {
307 while (connected() && !session_
->IsCryptoHandshakeConfirmed()) {
312 bool QuicClient::WaitForEvents() {
315 epoll_server_
->WaitForEventsAndExecuteCallbacks();
316 return session_
->num_active_requests() != 0;
319 bool QuicClient::MigrateSocket(const IPAddressNumber
& new_host
) {
326 bind_to_address_
= new_host
;
327 if (!CreateUDPSocket()) {
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);
344 void QuicClient::OnEvent(int fd
, EpollEvent
* event
) {
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
,
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
,
426 bool QuicClient::ReadAndProcessPacket() {
427 // Allocate some extra space so we can send an error if the server goes over
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) {
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
);