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/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"
26
27#ifndef SO_RXQ_OVFL
28#define SO_RXQ_OVFL 40
29#endif
30
31namespace net {
32namespace tools {
33
34const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
35
36QuicClient::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();
53}
54
55QuicClient::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) {
73}
74
75QuicClient::~QuicClient() {
76  if (connected()) {
77    session()->connection()->SendConnectionClosePacket(
78        QUIC_PEER_GOING_AWAY, "");
79  }
80  if (fd_ > 0) {
81    epoll_server_->UnregisterFD(fd_);
82  }
83}
84
85bool QuicClient::Initialize() {
86  DCHECK(!initialized_);
87
88  epoll_server_->set_timeout_in_us(50 * 1000);
89  crypto_config_.SetDefaults();
90
91  if (!CreateUDPSocket()) {
92    return false;
93  }
94
95  epoll_server_->RegisterFD(fd_, this, kEpollFlags);
96  initialized_ = true;
97  return true;
98}
99
100QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
101    QuicPacketWriter* writer)
102    : writer_(writer) {}
103
104QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
105
106QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
107    QuicConnection* /*connection*/) const {
108  return writer_;
109}
110
111
112bool 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;
118  }
119
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;
127  }
128
129  if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
130                                             TcpReceiver::kReceiveWindowTCP)) {
131    return false;
132  }
133
134  if (!QuicSocketUtils::SetSendBufferSize(fd_,
135                                          TcpReceiver::kReceiveWindowTCP)) {
136    return false;
137  }
138
139  rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
140  if (rc < 0) {
141    LOG(ERROR) << "IP detection not supported" << strerror(errno);
142    return false;
143  }
144
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_);
155  }
156
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;
167  }
168
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);
173  }
174
175  return true;
176}
177
178bool QuicClient::Connect() {
179  if (!StartConnect()) {
180    return false;
181  }
182  while (EncryptionBeingEstablished()) {
183    WaitForEvents();
184  }
185  return session_->connection()->connected();
186}
187
188bool QuicClient::StartConnect() {
189  DCHECK(initialized_);
190  DCHECK(!connected());
191
192  QuicPacketWriter* writer = CreateQuicPacketWriter();
193
194  DummyPacketWriterFactory factory(writer);
195
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_)));
205
206  // Reset |writer_| after |session_| so that the old writer outlives the old
207  // session.
208  if (writer_.get() != writer) {
209    writer_.reset(writer);
210  }
211  session_->InitializeSession(server_id_, &crypto_config_);
212  return session_->CryptoConnect();
213}
214
215bool QuicClient::EncryptionBeingEstablished() {
216  return !session_->IsEncryptionEstablished() &&
217      session_->connection()->connected();
218}
219
220void QuicClient::Disconnect() {
221  DCHECK(initialized_);
222
223  if (connected()) {
224    session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
225  }
226  epoll_server_->UnregisterFD(fd_);
227  close(fd_);
228  fd_ = -1;
229  initialized_ = false;
230}
231
232void 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);
241  }
242
243  while (WaitForEvents()) {}
244}
245
246QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
247  if (!connected()) {
248    return NULL;
249  }
250
251  return session_->CreateOutgoingDataStream();
252}
253
254void QuicClient::WaitForStreamToClose(QuicStreamId id) {
255  DCHECK(connected());
256
257  while (connected() && !session_->IsClosedStream(id)) {
258    epoll_server_->WaitForEventsAndExecuteCallbacks();
259  }
260}
261
262void QuicClient::WaitForCryptoHandshakeConfirmed() {
263  DCHECK(connected());
264
265  while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
266    epoll_server_->WaitForEventsAndExecuteCallbacks();
267  }
268}
269
270bool QuicClient::WaitForEvents() {
271  DCHECK(connected());
272
273  epoll_server_->WaitForEventsAndExecuteCallbacks();
274  return session_->num_active_requests() != 0;
275}
276
277void QuicClient::OnEvent(int fd, EpollEvent* event) {
278  DCHECK_EQ(fd, fd_);
279
280  if (event->in_events & EPOLLIN) {
281    while (connected() && ReadAndProcessPacket()) {
282    }
283  }
284  if (connected() && (event->in_events & EPOLLOUT)) {
285    writer_->SetWritable();
286    session_->connection()->OnCanWrite();
287  }
288  if (event->in_events & EPOLLERR) {
289    DVLOG(1) << "Epollerr";
290  }
291}
292
293void 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());
299  }
300
301  if (!print_response_) {
302    return;
303  }
304
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());
312  }
313  printf("%s\n", client_stream->data().c_str());
314}
315
316bool QuicClient::connected() const {
317  return session_.get() && session_->connection() &&
318      session_->connection()->connected();
319}
320
321QuicConnectionId QuicClient::GenerateConnectionId() {
322  return QuicRandom::GetInstance()->RandUint64();
323}
324
325QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
326  return new QuicEpollConnectionHelper(epoll_server_);
327}
328
329QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
330  return new QuicDefaultPacketWriter(fd_);
331}
332
333int 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);
340}
341
342bool 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];
346
347  IPEndPoint server_address;
348  IPAddressNumber client_ip;
349
350  int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
351
352  if (bytes_read < 0) {
353    return false;
354  }
355
356  QuicEncryptedPacket packet(buf, bytes_read, false);
357
358  IPEndPoint client_address(client_ip, client_address_.port());
359  session_->connection()->ProcessUdpPacket(
360      client_address, server_address, packet);
361  return true;
362}
363
364}  // namespace tools
365}  // namespace net
366