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 : server_address_(server_address
),
45 server_id_(server_id
),
47 epoll_server_(epoll_server
),
49 helper_(CreateQuicConnectionHelper()),
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
),
67 epoll_server_(epoll_server
),
69 helper_(CreateQuicConnectionHelper()),
72 overflow_supported_(false),
73 supported_versions_(supported_versions
),
74 store_response_(false),
75 latest_response_code_(-1) {
78 QuicClient::~QuicClient() {
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()) {
108 epoll_server_
->RegisterFD(fd_
, this, kEpollFlags
);
113 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
114 QuicPacketWriter
* writer
)
117 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
119 QuicPacketWriter
* QuicClient::DummyPacketWriterFactory::Create(
120 QuicConnection
* /*connection*/) const {
125 bool QuicClient::CreateUDPSocket() {
126 int address_family
= server_address_
.GetSockAddrFamily();
127 fd_
= socket(address_family
, SOCK_DGRAM
| SOCK_NONBLOCK
, IPPROTO_UDP
);
129 LOG(ERROR
) << "CreateSocket() failed: " << strerror(errno
);
133 int get_overflow
= 1;
134 int rc
= setsockopt(fd_
, SOL_SOCKET
, SO_RXQ_OVFL
, &get_overflow
,
135 sizeof(get_overflow
));
137 DLOG(WARNING
) << "Socket overflow detection not supported";
139 overflow_supported_
= true;
142 if (!QuicSocketUtils::SetReceiveBufferSize(fd_
,
143 kDefaultSocketReceiveBuffer
)) {
147 if (!QuicSocketUtils::SetSendBufferSize(fd_
, kDefaultSocketReceiveBuffer
)) {
151 rc
= QuicSocketUtils::SetGetAddressInfo(fd_
, address_family
);
153 LOG(ERROR
) << "IP detection not supported" << strerror(errno
);
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_
);
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
),
174 reinterpret_cast<const sockaddr
*>(&raw_addr
),
177 LOG(ERROR
) << "Bind failed: " << strerror(errno
);
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
);
190 bool QuicClient::Connect() {
192 while (EncryptionBeingEstablished()) {
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(
216 new QuicConnection(GenerateConnectionId(), server_address_
, helper_
.get(),
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
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_
);
240 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
245 initialized_
= false;
248 void QuicClient::CleanUpUDPSocket() {
249 CleanUpUDPSocketImpl();
252 void QuicClient::CleanUpUDPSocketImpl() {
254 epoll_server_
->UnregisterFD(fd_
);
261 void QuicClient::SendRequest(const BalsaHeaders
& headers
,
264 QuicSpdyClientStream
* stream
= CreateReliableClientStream();
265 if (stream
== nullptr) {
266 LOG(DFATAL
) << "stream creation failed!";
270 SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers
, stream
->version()),
272 stream
->set_visitor(this);
275 void QuicClient::SendRequestAndWaitForResponse(
276 const BalsaHeaders
& headers
,
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() {
298 return session_
->CreateOutgoingDataStream();
301 void QuicClient::WaitForStreamToClose(QuicStreamId id
) {
304 while (connected() && !session_
->IsClosedStream(id
)) {
309 void QuicClient::WaitForCryptoHandshakeConfirmed() {
312 while (connected() && !session_
->IsCryptoHandshakeConfirmed()) {
317 bool QuicClient::WaitForEvents() {
320 epoll_server_
->WaitForEventsAndExecuteCallbacks();
321 return session_
->num_active_requests() != 0;
324 void QuicClient::OnEvent(int fd
, EpollEvent
* event
) {
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
,
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
,
406 bool QuicClient::ReadAndProcessPacket() {
407 // Allocate some extra space so we can send an error if the server goes over
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) {
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
);