quic_client.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.
4
5#include "net/tools/quic/quic_client.h"
6
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>
13
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/balsa/balsa_headers.h"
20#include "net/tools/quic/quic_epoll_connection_helper.h"
21#include "net/tools/quic/quic_socket_utils.h"
22#include "net/tools/quic/quic_spdy_client_stream.h"
23
24#ifndef SO_RXQ_OVFL
25#define SO_RXQ_OVFL 40
26#endif
27
28namespace net {
29namespace tools {
30
31const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
32
33QuicClient::QuicClient(IPEndPoint server_address,
34                       const string& server_hostname,
35                       const QuicVersionVector& supported_versions,
36                       bool print_response)
37    : server_address_(server_address),
38      server_hostname_(server_hostname),
39      local_port_(0),
40      fd_(-1),
41      helper_(CreateQuicConnectionHelper()),
42      initialized_(false),
43      packets_dropped_(0),
44      overflow_supported_(false),
45      supported_versions_(supported_versions),
46      print_response_(print_response) {
47  config_.SetDefaults();
48}
49
50QuicClient::QuicClient(IPEndPoint server_address,
51                       const string& server_hostname,
52                       const QuicConfig& config,
53                       const QuicVersionVector& supported_versions)
54    : server_address_(server_address),
55      server_hostname_(server_hostname),
56      config_(config),
57      local_port_(0),
58      fd_(-1),
59      helper_(CreateQuicConnectionHelper()),
60      initialized_(false),
61      packets_dropped_(0),
62      overflow_supported_(false),
63      supported_versions_(supported_versions),
64      print_response_(false) {
65}
66
67QuicClient::~QuicClient() {
68  if (connected()) {
69    session()->connection()->SendConnectionClosePacket(
70        QUIC_PEER_GOING_AWAY, "");
71  }
72}
73
74bool QuicClient::Initialize() {
75  DCHECK(!initialized_);
76
77  epoll_server_.set_timeout_in_us(50 * 1000);
78  crypto_config_.SetDefaults();
79
80  int address_family = server_address_.GetSockAddrFamily();
81  fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
82  if (fd_ < 0) {
83    LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
84    return false;
85  }
86
87  int get_overflow = 1;
88  int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
89                      sizeof(get_overflow));
90  if (rc < 0) {
91    DLOG(WARNING) << "Socket overflow detection not supported";
92  } else {
93    overflow_supported_ = true;
94  }
95
96  int get_local_ip = 1;
97  if (address_family == AF_INET) {
98    rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
99                    &get_local_ip, sizeof(get_local_ip));
100  } else {
101    rc =  setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
102                     &get_local_ip, sizeof(get_local_ip));
103  }
104
105  if (rc < 0) {
106    LOG(ERROR) << "IP detection not supported" << strerror(errno);
107    return false;
108  }
109
110  if (bind_to_address_.size() != 0) {
111    client_address_ = IPEndPoint(bind_to_address_, local_port_);
112  } else if (address_family == AF_INET) {
113    IPAddressNumber any4;
114    CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
115    client_address_ = IPEndPoint(any4, local_port_);
116  } else {
117    IPAddressNumber any6;
118    CHECK(net::ParseIPLiteralToNumber("::", &any6));
119    client_address_ = IPEndPoint(any6, local_port_);
120  }
121
122  sockaddr_storage raw_addr;
123  socklen_t raw_addr_len = sizeof(raw_addr);
124  CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
125                           &raw_addr_len));
126  rc = bind(fd_,
127            reinterpret_cast<const sockaddr*>(&raw_addr),
128            sizeof(raw_addr));
129  if (rc < 0) {
130    LOG(ERROR) << "Bind failed: " << strerror(errno);
131    return false;
132  }
133
134  SockaddrStorage storage;
135  if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
136      !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
137    LOG(ERROR) << "Unable to get self address.  Error: " << strerror(errno);
138  }
139
140  epoll_server_.RegisterFD(fd_, this, kEpollFlags);
141  initialized_ = true;
142  return true;
143}
144
145bool QuicClient::Connect() {
146  if (!StartConnect()) {
147    return false;
148  }
149  while (EncryptionBeingEstablished()) {
150    WaitForEvents();
151  }
152  return session_->connection()->connected();
153}
154
155bool QuicClient::StartConnect() {
156  DCHECK(initialized_);
157  DCHECK(!connected());
158
159  QuicPacketWriter* writer = CreateQuicPacketWriter();
160  if (writer_.get() != writer) {
161    writer_.reset(writer);
162  }
163
164  session_.reset(new QuicClientSession(
165      server_hostname_,
166      config_,
167      new QuicConnection(GenerateGuid(), server_address_, helper_.get(),
168                         writer_.get(), false, supported_versions_),
169      &crypto_config_));
170  return session_->CryptoConnect();
171}
172
173bool QuicClient::EncryptionBeingEstablished() {
174  return !session_->IsEncryptionEstablished() &&
175      session_->connection()->connected();
176}
177
178void QuicClient::Disconnect() {
179  DCHECK(initialized_);
180
181  if (connected()) {
182    session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
183  }
184  epoll_server_.UnregisterFD(fd_);
185  close(fd_);
186  fd_ = -1;
187  initialized_ = false;
188}
189
190void QuicClient::SendRequestsAndWaitForResponse(
191    const CommandLine::StringVector& args) {
192  for (size_t i = 0; i < args.size(); ++i) {
193    BalsaHeaders headers;
194    headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
195    QuicSpdyClientStream* stream = CreateReliableClientStream();
196    stream->SendRequest(headers, "", true);
197    stream->set_visitor(this);
198  }
199
200  while (WaitForEvents()) { }
201}
202
203QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
204  if (!connected()) {
205    return NULL;
206  }
207
208  return session_->CreateOutgoingDataStream();
209}
210
211void QuicClient::WaitForStreamToClose(QuicStreamId id) {
212  DCHECK(connected());
213
214  while (!session_->IsClosedStream(id)) {
215    epoll_server_.WaitForEventsAndExecuteCallbacks();
216  }
217}
218
219void QuicClient::WaitForCryptoHandshakeConfirmed() {
220  DCHECK(connected());
221
222  while (!session_->IsCryptoHandshakeConfirmed()) {
223    epoll_server_.WaitForEventsAndExecuteCallbacks();
224  }
225}
226
227bool QuicClient::WaitForEvents() {
228  DCHECK(connected());
229
230  epoll_server_.WaitForEventsAndExecuteCallbacks();
231  return session_->num_active_requests() != 0;
232}
233
234void QuicClient::OnEvent(int fd, EpollEvent* event) {
235  DCHECK_EQ(fd, fd_);
236
237  if (event->in_events & EPOLLIN) {
238    while (connected() && ReadAndProcessPacket()) {
239    }
240  }
241  if (connected() && (event->in_events & EPOLLOUT)) {
242    writer_->SetWritable();
243    session_->connection()->OnCanWrite();
244  }
245  if (event->in_events & EPOLLERR) {
246    DVLOG(1) << "Epollerr";
247  }
248}
249
250void QuicClient::OnClose(QuicDataStream* stream) {
251  QuicSpdyClientStream* client_stream =
252      static_cast<QuicSpdyClientStream*>(stream);
253  if (response_listener_.get() != NULL) {
254    response_listener_->OnCompleteResponse(
255        stream->id(), client_stream->headers(), client_stream->data());
256  }
257
258  if (!print_response_) {
259    return;
260  }
261
262  const BalsaHeaders& headers = client_stream->headers();
263  printf("%s\n", headers.first_line().as_string().c_str());
264  for (BalsaHeaders::const_header_lines_iterator i =
265           headers.header_lines_begin();
266       i != headers.header_lines_end(); ++i) {
267    printf("%s: %s\n", i->first.as_string().c_str(),
268           i->second.as_string().c_str());
269  }
270  printf("%s\n", client_stream->data().c_str());
271}
272
273QuicPacketCreator::Options* QuicClient::options() {
274  if (session() == NULL) {
275    return NULL;
276  }
277  return session_->options();
278}
279
280bool QuicClient::connected() const {
281  return session_.get() && session_->connection() &&
282      session_->connection()->connected();
283}
284
285QuicGuid QuicClient::GenerateGuid() {
286  return QuicRandom::GetInstance()->RandUint64();
287}
288
289QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
290  return new QuicEpollConnectionHelper(&epoll_server_);
291}
292
293QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
294  return new QuicDefaultPacketWriter(fd_);
295}
296
297bool QuicClient::ReadAndProcessPacket() {
298  // Allocate some extra space so we can send an error if the server goes over
299  // the limit.
300  char buf[2 * kMaxPacketSize];
301
302  IPEndPoint server_address;
303  IPAddressNumber client_ip;
304
305  int bytes_read = QuicSocketUtils::ReadPacket(
306      fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
307      &client_ip, &server_address);
308
309  if (bytes_read < 0) {
310    return false;
311  }
312
313  QuicEncryptedPacket packet(buf, bytes_read, false);
314
315  IPEndPoint client_address(client_ip, client_address_.port());
316  session_->connection()->ProcessUdpPacket(
317      client_address, server_address, packet);
318  return true;
319}
320
321}  // namespace tools
322}  // namespace net
323