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/tools/flip_server/balsa_headers.h"
20 #include "net/tools/quic/quic_epoll_connection_helper.h"
21 #include "net/tools/quic/quic_reliable_client_stream.h"
22 #include "net/tools/quic/quic_socket_utils.h"
25 #define SO_RXQ_OVFL 40
31 const int kEpollFlags
= EPOLLIN
| EPOLLOUT
| EPOLLET
;
33 QuicClient::QuicClient(IPEndPoint server_address
,
34 const string
& server_hostname
,
35 const QuicVersion version
)
36 : server_address_(server_address
),
37 server_hostname_(server_hostname
),
42 overflow_supported_(false),
44 config_
.SetDefaults();
47 QuicClient::QuicClient(IPEndPoint server_address
,
48 const string
& server_hostname
,
49 const QuicConfig
& config
,
50 const QuicVersion version
)
51 : server_address_(server_address
),
52 server_hostname_(server_hostname
),
58 overflow_supported_(false),
62 QuicClient::~QuicClient() {
64 session()->connection()->SendConnectionClosePacket(
65 QUIC_PEER_GOING_AWAY
, "");
69 bool QuicClient::Initialize() {
70 DCHECK(!initialized_
);
72 epoll_server_
.set_timeout_in_us(50 * 1000);
73 crypto_config_
.SetDefaults();
75 int address_family
= server_address_
.GetSockAddrFamily();
76 fd_
= socket(address_family
, SOCK_DGRAM
| SOCK_NONBLOCK
, IPPROTO_UDP
);
78 LOG(ERROR
) << "CreateSocket() failed: " << strerror(errno
);
83 int rc
= setsockopt(fd_
, SOL_SOCKET
, SO_RXQ_OVFL
, &get_overflow
,
84 sizeof(get_overflow
));
86 DLOG(WARNING
) << "Socket overflow detection not supported";
88 overflow_supported_
= true;
92 if (address_family
== AF_INET
) {
93 rc
= setsockopt(fd_
, IPPROTO_IP
, IP_PKTINFO
,
94 &get_local_ip
, sizeof(get_local_ip
));
96 rc
= setsockopt(fd_
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
97 &get_local_ip
, sizeof(get_local_ip
));
101 LOG(ERROR
) << "IP detection not supported" << strerror(errno
);
105 if (bind_to_address_
.size() != 0) {
106 client_address_
= IPEndPoint(bind_to_address_
, local_port_
);
107 } else if (address_family
== AF_INET
) {
108 IPAddressNumber any4
;
109 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4
));
110 client_address_
= IPEndPoint(any4
, local_port_
);
112 IPAddressNumber any6
;
113 CHECK(net::ParseIPLiteralToNumber("::", &any6
));
114 client_address_
= IPEndPoint(any6
, local_port_
);
117 sockaddr_storage raw_addr
;
118 socklen_t raw_addr_len
= sizeof(raw_addr
);
119 CHECK(client_address_
.ToSockAddr(reinterpret_cast<sockaddr
*>(&raw_addr
),
122 reinterpret_cast<const sockaddr
*>(&raw_addr
),
125 LOG(ERROR
) << "Bind failed: " << strerror(errno
);
129 SockaddrStorage storage
;
130 if (getsockname(fd_
, storage
.addr
, &storage
.addr_len
) != 0 ||
131 !client_address_
.FromSockAddr(storage
.addr
, storage
.addr_len
)) {
132 LOG(ERROR
) << "Unable to get self address. Error: " << strerror(errno
);
135 epoll_server_
.RegisterFD(fd_
, this, kEpollFlags
);
140 bool QuicClient::Connect() {
141 if (!StartConnect()) {
144 while (EncryptionBeingEstablished()) {
147 return session_
->connection()->connected();
150 bool QuicClient::StartConnect() {
151 DCHECK(!connected() && initialized_
);
153 QuicGuid guid
= QuicRandom::GetInstance()->RandUint64();
154 session_
.reset(new QuicClientSession(
157 new QuicConnection(guid
, server_address_
,
158 CreateQuicConnectionHelper(), false,
161 return session_
->CryptoConnect();
164 bool QuicClient::EncryptionBeingEstablished() {
165 return !session_
->IsEncryptionEstablished() &&
166 session_
->connection()->connected();
169 void QuicClient::Disconnect() {
172 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY
);
173 epoll_server_
.UnregisterFD(fd_
);
176 initialized_
= false;
179 void QuicClient::SendRequestsAndWaitForResponse(
180 const CommandLine::StringVector
& args
) {
181 for (uint32_t i
= 0; i
< args
.size(); i
++) {
182 BalsaHeaders headers
;
183 headers
.SetRequestFirstlineFromStringPieces("GET", args
[i
], "HTTP/1.1");
184 CreateReliableClientStream()->SendRequest(headers
, "", true);
187 while (WaitForEvents()) { }
190 QuicReliableClientStream
* QuicClient::CreateReliableClientStream() {
195 return session_
->CreateOutgoingReliableStream();
198 void QuicClient::WaitForStreamToClose(QuicStreamId id
) {
201 while (!session_
->IsClosedStream(id
)) {
202 epoll_server_
.WaitForEventsAndExecuteCallbacks();
206 void QuicClient::WaitForCryptoHandshakeConfirmed() {
209 while (!session_
->IsCryptoHandshakeConfirmed()) {
210 epoll_server_
.WaitForEventsAndExecuteCallbacks();
214 bool QuicClient::WaitForEvents() {
217 epoll_server_
.WaitForEventsAndExecuteCallbacks();
218 return session_
->num_active_requests() != 0;
221 void QuicClient::OnEvent(int fd
, EpollEvent
* event
) {
224 if (event
->in_events
& EPOLLIN
) {
225 while (connected() && ReadAndProcessPacket()) {
228 if (connected() && (event
->in_events
& EPOLLOUT
)) {
229 session_
->connection()->OnCanWrite();
231 if (event
->in_events
& EPOLLERR
) {
232 DLOG(INFO
) << "Epollerr";
236 QuicPacketCreator::Options
* QuicClient::options() {
237 if (session() == NULL
) {
240 return session_
->options();
243 bool QuicClient::connected() const {
244 return session_
.get() && session_
->connection() &&
245 session_
->connection()->connected();
248 QuicEpollConnectionHelper
* QuicClient::CreateQuicConnectionHelper() {
249 return new QuicEpollConnectionHelper(fd_
, &epoll_server_
);
252 bool QuicClient::ReadAndProcessPacket() {
253 // Allocate some extra space so we can send an error if the server goes over
255 char buf
[2 * kMaxPacketSize
];
257 IPEndPoint server_address
;
258 IPAddressNumber client_ip
;
260 int bytes_read
= QuicSocketUtils::ReadPacket(
261 fd_
, buf
, arraysize(buf
), overflow_supported_
? &packets_dropped_
: NULL
,
262 &client_ip
, &server_address
);
264 if (bytes_read
< 0) {
268 QuicEncryptedPacket
packet(buf
, bytes_read
, false);
269 QuicGuid our_guid
= session_
->connection()->guid();
270 QuicGuid packet_guid
;
272 if (!QuicFramer::ReadGuidFromPacket(packet
, &packet_guid
)) {
273 DLOG(INFO
) << "Could not read GUID from packet";
276 if (packet_guid
!= our_guid
) {
277 DLOG(INFO
) << "Ignoring packet from unexpected GUID: "
278 << packet_guid
<< " instead of " << our_guid
;
282 IPEndPoint
client_address(client_ip
, client_address_
.port());
283 session_
->connection()->ProcessUdpPacket(
284 client_address
, server_address
, packet
);