Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blob48f789fac555836905aed1b1f052cebbb4ca605d
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/congestion_control/tcp_receiver.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"
27 #ifndef SO_RXQ_OVFL
28 #define SO_RXQ_OVFL 40
29 #endif
31 namespace net {
32 namespace tools {
34 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
36 QuicClient::QuicClient(IPEndPoint server_address,
37 const QuicServerId& server_id,
38 const QuicVersionVector& supported_versions,
39 bool print_response,
40 EpollServer* epoll_server)
41 : server_address_(server_address),
42 server_id_(server_id),
43 local_port_(0),
44 epoll_server_(epoll_server),
45 fd_(-1),
46 helper_(CreateQuicConnectionHelper()),
47 initialized_(false),
48 packets_dropped_(0),
49 overflow_supported_(false),
50 supported_versions_(supported_versions),
51 print_response_(print_response) {
52 config_.SetDefaults();
55 QuicClient::QuicClient(IPEndPoint server_address,
56 const QuicServerId& server_id,
57 const QuicVersionVector& supported_versions,
58 bool print_response,
59 const QuicConfig& config,
60 EpollServer* epoll_server)
61 : server_address_(server_address),
62 server_id_(server_id),
63 config_(config),
64 local_port_(0),
65 epoll_server_(epoll_server),
66 fd_(-1),
67 helper_(CreateQuicConnectionHelper()),
68 initialized_(false),
69 packets_dropped_(0),
70 overflow_supported_(false),
71 supported_versions_(supported_versions),
72 print_response_(print_response) {
75 QuicClient::~QuicClient() {
76 if (connected()) {
77 session()->connection()->SendConnectionClosePacket(
78 QUIC_PEER_GOING_AWAY, "");
80 if (fd_ > 0) {
81 epoll_server_->UnregisterFD(fd_);
85 bool QuicClient::Initialize() {
86 DCHECK(!initialized_);
88 epoll_server_->set_timeout_in_us(50 * 1000);
89 crypto_config_.SetDefaults();
91 if (!CreateUDPSocket()) {
92 return false;
95 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
96 initialized_ = true;
97 return true;
100 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
101 QuicPacketWriter* writer)
102 : writer_(writer) {}
104 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
106 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
107 QuicConnection* /*connection*/) const {
108 return writer_;
112 bool QuicClient::CreateUDPSocket() {
113 int address_family = server_address_.GetSockAddrFamily();
114 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
115 if (fd_ < 0) {
116 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
117 return false;
120 int get_overflow = 1;
121 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
122 sizeof(get_overflow));
123 if (rc < 0) {
124 DLOG(WARNING) << "Socket overflow detection not supported";
125 } else {
126 overflow_supported_ = true;
129 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
130 TcpReceiver::kReceiveWindowTCP)) {
131 return false;
134 if (!QuicSocketUtils::SetSendBufferSize(fd_,
135 TcpReceiver::kReceiveWindowTCP)) {
136 return false;
139 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
140 if (rc < 0) {
141 LOG(ERROR) << "IP detection not supported" << strerror(errno);
142 return false;
145 if (bind_to_address_.size() != 0) {
146 client_address_ = IPEndPoint(bind_to_address_, local_port_);
147 } else if (address_family == AF_INET) {
148 IPAddressNumber any4;
149 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
150 client_address_ = IPEndPoint(any4, local_port_);
151 } else {
152 IPAddressNumber any6;
153 CHECK(net::ParseIPLiteralToNumber("::", &any6));
154 client_address_ = IPEndPoint(any6, local_port_);
157 sockaddr_storage raw_addr;
158 socklen_t raw_addr_len = sizeof(raw_addr);
159 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
160 &raw_addr_len));
161 rc = bind(fd_,
162 reinterpret_cast<const sockaddr*>(&raw_addr),
163 sizeof(raw_addr));
164 if (rc < 0) {
165 LOG(ERROR) << "Bind failed: " << strerror(errno);
166 return false;
169 SockaddrStorage storage;
170 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
171 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
172 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
175 return true;
178 bool QuicClient::Connect() {
179 if (!StartConnect()) {
180 return false;
182 while (EncryptionBeingEstablished()) {
183 WaitForEvents();
185 return session_->connection()->connected();
188 bool QuicClient::StartConnect() {
189 DCHECK(initialized_);
190 DCHECK(!connected());
192 QuicPacketWriter* writer = CreateQuicPacketWriter();
194 DummyPacketWriterFactory factory(writer);
196 session_.reset(new QuicClientSession(
197 config_,
198 new QuicConnection(GenerateConnectionId(),
199 server_address_,
200 helper_.get(),
201 factory,
202 /* owns_writer= */ false,
203 /* is_server= */ false,
204 supported_versions_)));
206 // Reset |writer_| after |session_| so that the old writer outlives the old
207 // session.
208 if (writer_.get() != writer) {
209 writer_.reset(writer);
211 session_->InitializeSession(server_id_, &crypto_config_);
212 return session_->CryptoConnect();
215 bool QuicClient::EncryptionBeingEstablished() {
216 return !session_->IsEncryptionEstablished() &&
217 session_->connection()->connected();
220 void QuicClient::Disconnect() {
221 DCHECK(initialized_);
223 if (connected()) {
224 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
226 epoll_server_->UnregisterFD(fd_);
227 close(fd_);
228 fd_ = -1;
229 initialized_ = false;
232 void QuicClient::SendRequestsAndWaitForResponse(
233 const base::CommandLine::StringVector& args) {
234 for (size_t i = 0; i < args.size(); ++i) {
235 BalsaHeaders headers;
236 headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
237 QuicSpdyClientStream* stream = CreateReliableClientStream();
238 DCHECK(stream != NULL);
239 stream->SendRequest(headers, "", true);
240 stream->set_visitor(this);
243 while (WaitForEvents()) {}
246 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
247 if (!connected()) {
248 return NULL;
251 return session_->CreateOutgoingDataStream();
254 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
255 DCHECK(connected());
257 while (connected() && !session_->IsClosedStream(id)) {
258 epoll_server_->WaitForEventsAndExecuteCallbacks();
262 void QuicClient::WaitForCryptoHandshakeConfirmed() {
263 DCHECK(connected());
265 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
266 epoll_server_->WaitForEventsAndExecuteCallbacks();
270 bool QuicClient::WaitForEvents() {
271 DCHECK(connected());
273 epoll_server_->WaitForEventsAndExecuteCallbacks();
274 return session_->num_active_requests() != 0;
277 void QuicClient::OnEvent(int fd, EpollEvent* event) {
278 DCHECK_EQ(fd, fd_);
280 if (event->in_events & EPOLLIN) {
281 while (connected() && ReadAndProcessPacket()) {
284 if (connected() && (event->in_events & EPOLLOUT)) {
285 writer_->SetWritable();
286 session_->connection()->OnCanWrite();
288 if (event->in_events & EPOLLERR) {
289 DVLOG(1) << "Epollerr";
293 void QuicClient::OnClose(QuicDataStream* stream) {
294 QuicSpdyClientStream* client_stream =
295 static_cast<QuicSpdyClientStream*>(stream);
296 if (response_listener_.get() != NULL) {
297 response_listener_->OnCompleteResponse(
298 stream->id(), client_stream->headers(), client_stream->data());
301 if (!print_response_) {
302 return;
305 const BalsaHeaders& headers = client_stream->headers();
306 printf("%s\n", headers.first_line().as_string().c_str());
307 for (BalsaHeaders::const_header_lines_iterator i =
308 headers.header_lines_begin();
309 i != headers.header_lines_end(); ++i) {
310 printf("%s: %s\n", i->first.as_string().c_str(),
311 i->second.as_string().c_str());
313 printf("%s\n", client_stream->data().c_str());
316 bool QuicClient::connected() const {
317 return session_.get() && session_->connection() &&
318 session_->connection()->connected();
321 QuicConnectionId QuicClient::GenerateConnectionId() {
322 return QuicRandom::GetInstance()->RandUint64();
325 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
326 return new QuicEpollConnectionHelper(epoll_server_);
329 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
330 return new QuicDefaultPacketWriter(fd_);
333 int QuicClient::ReadPacket(char* buffer,
334 int buffer_len,
335 IPEndPoint* server_address,
336 IPAddressNumber* client_ip) {
337 return QuicSocketUtils::ReadPacket(
338 fd_, buffer, buffer_len, overflow_supported_ ? &packets_dropped_ : NULL,
339 client_ip, server_address);
342 bool QuicClient::ReadAndProcessPacket() {
343 // Allocate some extra space so we can send an error if the server goes over
344 // the limit.
345 char buf[2 * kMaxPacketSize];
347 IPEndPoint server_address;
348 IPAddressNumber client_ip;
350 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
352 if (bytes_read < 0) {
353 return false;
356 QuicEncryptedPacket packet(buf, bytes_read, false);
358 IPEndPoint client_address(client_ip, client_address_.port());
359 session_->connection()->ProcessUdpPacket(
360 client_address, server_address, packet);
361 return true;
364 } // namespace tools
365 } // namespace net