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/quic/crypto/quic_random.h"
16 #include "net/quic/quic_connection.h"
17 #include "net/quic/quic_data_reader.h"
18 #include "net/quic/quic_protocol.h"
19 #include "net/quic/quic_session_key.h"
20 #include "net/tools/balsa/balsa_headers.h"
21 #include "net/tools/quic/quic_epoll_connection_helper.h"
22 #include "net/tools/quic/quic_socket_utils.h"
23 #include "net/tools/quic/quic_spdy_client_stream.h"
26 #define SO_RXQ_OVFL 40
32 const int kEpollFlags
= EPOLLIN
| EPOLLOUT
| EPOLLET
;
34 QuicClient::QuicClient(IPEndPoint server_address
,
35 const QuicSessionKey
& server_key
,
36 const QuicVersionVector
& supported_versions
,
38 uint32 initial_flow_control_window
)
39 : server_address_(server_address
),
40 server_key_(server_key
),
43 helper_(CreateQuicConnectionHelper()),
46 overflow_supported_(false),
47 supported_versions_(supported_versions
),
48 print_response_(print_response
),
49 initial_flow_control_window_(initial_flow_control_window
) {
50 config_
.SetDefaults();
53 QuicClient::QuicClient(IPEndPoint server_address
,
54 const QuicSessionKey
& server_key
,
55 const QuicConfig
& config
,
56 const QuicVersionVector
& supported_versions
,
57 uint32 initial_flow_control_window
)
58 : server_address_(server_address
),
59 server_key_(server_key
),
63 helper_(CreateQuicConnectionHelper()),
66 overflow_supported_(false),
67 supported_versions_(supported_versions
),
68 print_response_(false),
69 initial_flow_control_window_(initial_flow_control_window
) {
72 QuicClient::~QuicClient() {
74 session()->connection()->SendConnectionClosePacket(
75 QUIC_PEER_GOING_AWAY
, "");
79 bool QuicClient::Initialize() {
80 DCHECK(!initialized_
);
82 epoll_server_
.set_timeout_in_us(50 * 1000);
83 crypto_config_
.SetDefaults();
85 int address_family
= server_address_
.GetSockAddrFamily();
86 fd_
= socket(address_family
, SOCK_DGRAM
| SOCK_NONBLOCK
, IPPROTO_UDP
);
88 LOG(ERROR
) << "CreateSocket() failed: " << strerror(errno
);
93 int rc
= setsockopt(fd_
, SOL_SOCKET
, SO_RXQ_OVFL
, &get_overflow
,
94 sizeof(get_overflow
));
96 DLOG(WARNING
) << "Socket overflow detection not supported";
98 overflow_supported_
= true;
101 int get_local_ip
= 1;
102 if (address_family
== AF_INET
) {
103 rc
= setsockopt(fd_
, IPPROTO_IP
, IP_PKTINFO
,
104 &get_local_ip
, sizeof(get_local_ip
));
106 rc
= setsockopt(fd_
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
107 &get_local_ip
, sizeof(get_local_ip
));
111 LOG(ERROR
) << "IP detection not supported" << strerror(errno
);
115 if (bind_to_address_
.size() != 0) {
116 client_address_
= IPEndPoint(bind_to_address_
, local_port_
);
117 } else if (address_family
== AF_INET
) {
118 IPAddressNumber any4
;
119 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4
));
120 client_address_
= IPEndPoint(any4
, local_port_
);
122 IPAddressNumber any6
;
123 CHECK(net::ParseIPLiteralToNumber("::", &any6
));
124 client_address_
= IPEndPoint(any6
, local_port_
);
127 sockaddr_storage raw_addr
;
128 socklen_t raw_addr_len
= sizeof(raw_addr
);
129 CHECK(client_address_
.ToSockAddr(reinterpret_cast<sockaddr
*>(&raw_addr
),
132 reinterpret_cast<const sockaddr
*>(&raw_addr
),
135 LOG(ERROR
) << "Bind failed: " << strerror(errno
);
139 SockaddrStorage storage
;
140 if (getsockname(fd_
, storage
.addr
, &storage
.addr_len
) != 0 ||
141 !client_address_
.FromSockAddr(storage
.addr
, storage
.addr_len
)) {
142 LOG(ERROR
) << "Unable to get self address. Error: " << strerror(errno
);
145 epoll_server_
.RegisterFD(fd_
, this, kEpollFlags
);
150 bool QuicClient::Connect() {
151 if (!StartConnect()) {
154 while (EncryptionBeingEstablished()) {
157 return session_
->connection()->connected();
160 bool QuicClient::StartConnect() {
161 DCHECK(initialized_
);
162 DCHECK(!connected());
164 QuicPacketWriter
* writer
= CreateQuicPacketWriter();
165 if (writer_
.get() != writer
) {
166 writer_
.reset(writer
);
169 session_
.reset(new QuicClientSession(
172 new QuicConnection(GenerateConnectionId(), server_address_
, helper_
.get(),
173 writer_
.get(), false, supported_versions_
,
174 initial_flow_control_window_
),
176 return session_
->CryptoConnect();
179 bool QuicClient::EncryptionBeingEstablished() {
180 return !session_
->IsEncryptionEstablished() &&
181 session_
->connection()->connected();
184 void QuicClient::Disconnect() {
185 DCHECK(initialized_
);
188 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
190 epoll_server_
.UnregisterFD(fd_
);
193 initialized_
= false;
196 void QuicClient::SendRequestsAndWaitForResponse(
197 const CommandLine::StringVector
& args
) {
198 for (size_t i
= 0; i
< args
.size(); ++i
) {
199 BalsaHeaders headers
;
200 headers
.SetRequestFirstlineFromStringPieces("GET", args
[i
], "HTTP/1.1");
201 QuicSpdyClientStream
* stream
= CreateReliableClientStream();
202 stream
->SendRequest(headers
, "", true);
203 stream
->set_visitor(this);
206 while (WaitForEvents()) { }
209 QuicSpdyClientStream
* QuicClient::CreateReliableClientStream() {
214 return session_
->CreateOutgoingDataStream();
217 void QuicClient::WaitForStreamToClose(QuicStreamId id
) {
220 while (!session_
->IsClosedStream(id
)) {
221 epoll_server_
.WaitForEventsAndExecuteCallbacks();
225 void QuicClient::WaitForCryptoHandshakeConfirmed() {
228 while (!session_
->IsCryptoHandshakeConfirmed()) {
229 epoll_server_
.WaitForEventsAndExecuteCallbacks();
233 bool QuicClient::WaitForEvents() {
236 epoll_server_
.WaitForEventsAndExecuteCallbacks();
237 return session_
->num_active_requests() != 0;
240 void QuicClient::OnEvent(int fd
, EpollEvent
* event
) {
243 if (event
->in_events
& EPOLLIN
) {
244 while (connected() && ReadAndProcessPacket()) {
247 if (connected() && (event
->in_events
& EPOLLOUT
)) {
248 writer_
->SetWritable();
249 session_
->connection()->OnCanWrite();
251 if (event
->in_events
& EPOLLERR
) {
252 DVLOG(1) << "Epollerr";
256 void QuicClient::OnClose(QuicDataStream
* stream
) {
257 QuicSpdyClientStream
* client_stream
=
258 static_cast<QuicSpdyClientStream
*>(stream
);
259 if (response_listener_
.get() != NULL
) {
260 response_listener_
->OnCompleteResponse(
261 stream
->id(), client_stream
->headers(), client_stream
->data());
264 if (!print_response_
) {
268 const BalsaHeaders
& headers
= client_stream
->headers();
269 printf("%s\n", headers
.first_line().as_string().c_str());
270 for (BalsaHeaders::const_header_lines_iterator i
=
271 headers
.header_lines_begin();
272 i
!= headers
.header_lines_end(); ++i
) {
273 printf("%s: %s\n", i
->first
.as_string().c_str(),
274 i
->second
.as_string().c_str());
276 printf("%s\n", client_stream
->data().c_str());
279 QuicPacketCreator::Options
* QuicClient::options() {
280 if (session() == NULL
) {
283 return session_
->options();
286 bool QuicClient::connected() const {
287 return session_
.get() && session_
->connection() &&
288 session_
->connection()->connected();
291 QuicConnectionId
QuicClient::GenerateConnectionId() {
292 return QuicRandom::GetInstance()->RandUint64();
295 QuicEpollConnectionHelper
* QuicClient::CreateQuicConnectionHelper() {
296 return new QuicEpollConnectionHelper(&epoll_server_
);
299 QuicPacketWriter
* QuicClient::CreateQuicPacketWriter() {
300 return new QuicDefaultPacketWriter(fd_
);
303 bool QuicClient::ReadAndProcessPacket() {
304 // Allocate some extra space so we can send an error if the server goes over
306 char buf
[2 * kMaxPacketSize
];
308 IPEndPoint server_address
;
309 IPAddressNumber client_ip
;
311 int bytes_read
= QuicSocketUtils::ReadPacket(
312 fd_
, buf
, arraysize(buf
), overflow_supported_
? &packets_dropped_
: NULL
,
313 &client_ip
, &server_address
);
315 if (bytes_read
< 0) {
319 QuicEncryptedPacket
packet(buf
, bytes_read
, false);
321 IPEndPoint
client_address(client_ip
, client_address_
.port());
322 session_
->connection()->ProcessUdpPacket(
323 client_address
, server_address
, packet
);