Land Recent QUIC Changes
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blobf0cca3b56918c84c36fe594069a7f990462e02ff
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/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"
25 #ifndef SO_RXQ_OVFL
26 #define SO_RXQ_OVFL 40
27 #endif
29 namespace net {
30 namespace tools {
32 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
34 QuicClient::QuicClient(IPEndPoint server_address,
35 const QuicSessionKey& server_key,
36 const QuicVersionVector& supported_versions,
37 bool print_response,
38 uint32 initial_flow_control_window)
39 : server_address_(server_address),
40 server_key_(server_key),
41 local_port_(0),
42 fd_(-1),
43 helper_(CreateQuicConnectionHelper()),
44 initialized_(false),
45 packets_dropped_(0),
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),
60 config_(config),
61 local_port_(0),
62 fd_(-1),
63 helper_(CreateQuicConnectionHelper()),
64 initialized_(false),
65 packets_dropped_(0),
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() {
73 if (connected()) {
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);
87 if (fd_ < 0) {
88 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
89 return false;
92 int get_overflow = 1;
93 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
94 sizeof(get_overflow));
95 if (rc < 0) {
96 DLOG(WARNING) << "Socket overflow detection not supported";
97 } else {
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));
105 } else {
106 rc = setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
107 &get_local_ip, sizeof(get_local_ip));
110 if (rc < 0) {
111 LOG(ERROR) << "IP detection not supported" << strerror(errno);
112 return false;
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_);
121 } else {
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),
130 &raw_addr_len));
131 rc = bind(fd_,
132 reinterpret_cast<const sockaddr*>(&raw_addr),
133 sizeof(raw_addr));
134 if (rc < 0) {
135 LOG(ERROR) << "Bind failed: " << strerror(errno);
136 return false;
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);
146 initialized_ = true;
147 return true;
150 bool QuicClient::Connect() {
151 if (!StartConnect()) {
152 return false;
154 while (EncryptionBeingEstablished()) {
155 WaitForEvents();
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(
170 server_key_,
171 config_,
172 new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
173 writer_.get(), false, supported_versions_,
174 initial_flow_control_window_),
175 &crypto_config_));
176 return session_->CryptoConnect();
179 bool QuicClient::EncryptionBeingEstablished() {
180 return !session_->IsEncryptionEstablished() &&
181 session_->connection()->connected();
184 void QuicClient::Disconnect() {
185 DCHECK(initialized_);
187 if (connected()) {
188 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
190 epoll_server_.UnregisterFD(fd_);
191 close(fd_);
192 fd_ = -1;
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() {
210 if (!connected()) {
211 return NULL;
214 return session_->CreateOutgoingDataStream();
217 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
218 DCHECK(connected());
220 while (!session_->IsClosedStream(id)) {
221 epoll_server_.WaitForEventsAndExecuteCallbacks();
225 void QuicClient::WaitForCryptoHandshakeConfirmed() {
226 DCHECK(connected());
228 while (!session_->IsCryptoHandshakeConfirmed()) {
229 epoll_server_.WaitForEventsAndExecuteCallbacks();
233 bool QuicClient::WaitForEvents() {
234 DCHECK(connected());
236 epoll_server_.WaitForEventsAndExecuteCallbacks();
237 return session_->num_active_requests() != 0;
240 void QuicClient::OnEvent(int fd, EpollEvent* event) {
241 DCHECK_EQ(fd, fd_);
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_) {
265 return;
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) {
281 return 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
305 // the limit.
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) {
316 return false;
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);
324 return true;
327 } // namespace tools
328 } // namespace net