Home | History | Annotate | Download | only in quic
      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/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"
     23 
     24 #ifndef SO_RXQ_OVFL
     25 #define SO_RXQ_OVFL 40
     26 #endif
     27 
     28 namespace net {
     29 namespace tools {
     30 
     31 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
     32 
     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),
     38       local_port_(0),
     39       fd_(-1),
     40       initialized_(false),
     41       packets_dropped_(0),
     42       overflow_supported_(false),
     43       version_(version) {
     44   config_.SetDefaults();
     45 }
     46 
     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),
     53       config_(config),
     54       local_port_(0),
     55       fd_(-1),
     56       initialized_(false),
     57       packets_dropped_(0),
     58       overflow_supported_(false),
     59       version_(version) {
     60 }
     61 
     62 QuicClient::~QuicClient() {
     63   if (connected()) {
     64     session()->connection()->SendConnectionClosePacket(
     65         QUIC_PEER_GOING_AWAY, "");
     66   }
     67 }
     68 
     69 bool QuicClient::Initialize() {
     70   DCHECK(!initialized_);
     71 
     72   epoll_server_.set_timeout_in_us(50 * 1000);
     73   crypto_config_.SetDefaults();
     74 
     75   int address_family = server_address_.GetSockAddrFamily();
     76   fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
     77   if (fd_ < 0) {
     78     LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
     79     return false;
     80   }
     81 
     82   int get_overflow = 1;
     83   int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
     84                       sizeof(get_overflow));
     85   if (rc < 0) {
     86     DLOG(WARNING) << "Socket overflow detection not supported";
     87   } else {
     88     overflow_supported_ = true;
     89   }
     90 
     91   int get_local_ip = 1;
     92   if (address_family == AF_INET) {
     93     rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
     94                     &get_local_ip, sizeof(get_local_ip));
     95   } else {
     96     rc =  setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
     97                      &get_local_ip, sizeof(get_local_ip));
     98   }
     99 
    100   if (rc < 0) {
    101     LOG(ERROR) << "IP detection not supported" << strerror(errno);
    102     return false;
    103   }
    104 
    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_);
    111   } else {
    112     IPAddressNumber any6;
    113     CHECK(net::ParseIPLiteralToNumber("::", &any6));
    114     client_address_ = IPEndPoint(any6, local_port_);
    115   }
    116 
    117   sockaddr_storage raw_addr;
    118   socklen_t raw_addr_len = sizeof(raw_addr);
    119   CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
    120                            &raw_addr_len));
    121   rc = bind(fd_,
    122             reinterpret_cast<const sockaddr*>(&raw_addr),
    123             sizeof(raw_addr));
    124   if (rc < 0) {
    125     LOG(ERROR) << "Bind failed: " << strerror(errno);
    126     return false;
    127   }
    128 
    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);
    133   }
    134 
    135   epoll_server_.RegisterFD(fd_, this, kEpollFlags);
    136   initialized_ = true;
    137   return true;
    138 }
    139 
    140 bool QuicClient::Connect() {
    141   if (!StartConnect()) {
    142     return false;
    143   }
    144   while (EncryptionBeingEstablished()) {
    145     WaitForEvents();
    146   }
    147   return session_->connection()->connected();
    148 }
    149 
    150 bool QuicClient::StartConnect() {
    151   DCHECK(!connected() && initialized_);
    152 
    153   QuicGuid guid = QuicRandom::GetInstance()->RandUint64();
    154   session_.reset(new QuicClientSession(
    155       server_hostname_,
    156       config_,
    157       new QuicConnection(guid, server_address_,
    158                          CreateQuicConnectionHelper(), false,
    159                          version_),
    160       &crypto_config_));
    161   return session_->CryptoConnect();
    162 }
    163 
    164 bool QuicClient::EncryptionBeingEstablished() {
    165   return !session_->IsEncryptionEstablished() &&
    166       session_->connection()->connected();
    167 }
    168 
    169 void QuicClient::Disconnect() {
    170   DCHECK(connected());
    171 
    172   session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
    173   epoll_server_.UnregisterFD(fd_);
    174   close(fd_);
    175   fd_ = -1;
    176   initialized_ = false;
    177 }
    178 
    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);
    185   }
    186 
    187   while (WaitForEvents()) { }
    188 }
    189 
    190 QuicReliableClientStream* QuicClient::CreateReliableClientStream() {
    191   if (!connected()) {
    192     return NULL;
    193   }
    194 
    195   return session_->CreateOutgoingReliableStream();
    196 }
    197 
    198 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
    199   DCHECK(connected());
    200 
    201   while (!session_->IsClosedStream(id)) {
    202     epoll_server_.WaitForEventsAndExecuteCallbacks();
    203   }
    204 }
    205 
    206 void QuicClient::WaitForCryptoHandshakeConfirmed() {
    207   DCHECK(connected());
    208 
    209   while (!session_->IsCryptoHandshakeConfirmed()) {
    210     epoll_server_.WaitForEventsAndExecuteCallbacks();
    211   }
    212 }
    213 
    214 bool QuicClient::WaitForEvents() {
    215   DCHECK(connected());
    216 
    217   epoll_server_.WaitForEventsAndExecuteCallbacks();
    218   return session_->num_active_requests() != 0;
    219 }
    220 
    221 void QuicClient::OnEvent(int fd, EpollEvent* event) {
    222   DCHECK_EQ(fd, fd_);
    223 
    224   if (event->in_events & EPOLLIN) {
    225     while (connected() && ReadAndProcessPacket()) {
    226     }
    227   }
    228   if (connected() && (event->in_events & EPOLLOUT)) {
    229     session_->connection()->OnCanWrite();
    230   }
    231   if (event->in_events & EPOLLERR) {
    232     DLOG(INFO) << "Epollerr";
    233   }
    234 }
    235 
    236 QuicPacketCreator::Options* QuicClient::options() {
    237   if (session() == NULL) {
    238     return NULL;
    239   }
    240   return session_->options();
    241 }
    242 
    243 bool QuicClient::connected() const {
    244   return session_.get() && session_->connection() &&
    245       session_->connection()->connected();
    246 }
    247 
    248 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
    249   return new QuicEpollConnectionHelper(fd_, &epoll_server_);
    250 }
    251 
    252 bool QuicClient::ReadAndProcessPacket() {
    253   // Allocate some extra space so we can send an error if the server goes over
    254   // the limit.
    255   char buf[2 * kMaxPacketSize];
    256 
    257   IPEndPoint server_address;
    258   IPAddressNumber client_ip;
    259 
    260   int bytes_read = QuicSocketUtils::ReadPacket(
    261       fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
    262       &client_ip, &server_address);
    263 
    264   if (bytes_read < 0) {
    265     return false;
    266   }
    267 
    268   QuicEncryptedPacket packet(buf, bytes_read, false);
    269   QuicGuid our_guid = session_->connection()->guid();
    270   QuicGuid packet_guid;
    271 
    272   if (!QuicFramer::ReadGuidFromPacket(packet, &packet_guid)) {
    273     DLOG(INFO) << "Could not read GUID from packet";
    274     return true;
    275   }
    276   if (packet_guid != our_guid) {
    277     DLOG(INFO) << "Ignoring packet from unexpected GUID: "
    278                << packet_guid << " instead of " << our_guid;
    279     return true;
    280   }
    281 
    282   IPEndPoint client_address(client_ip, client_address_.port());
    283   session_->connection()->ProcessUdpPacket(
    284       client_address, server_address, packet);
    285   return true;
    286 }
    287 
    288 }  // namespace tools
    289 }  // namespace net
    290