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/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 
     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 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 
     50 QuicClient::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 
     67 QuicClient::~QuicClient() {
     68   if (connected()) {
     69     session()->connection()->SendConnectionClosePacket(
     70         QUIC_PEER_GOING_AWAY, "");
     71   }
     72 }
     73 
     74 bool 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 
    145 bool QuicClient::Connect() {
    146   if (!StartConnect()) {
    147     return false;
    148   }
    149   while (EncryptionBeingEstablished()) {
    150     WaitForEvents();
    151   }
    152   return session_->connection()->connected();
    153 }
    154 
    155 bool QuicClient::StartConnect() {
    156   DCHECK(!connected() && initialized_);
    157 
    158   QuicPacketWriter* writer = CreateQuicPacketWriter();
    159   if (writer_.get() != writer) {
    160     writer_.reset(writer);
    161   }
    162 
    163   session_.reset(new QuicClientSession(
    164       server_hostname_,
    165       config_,
    166       new QuicConnection(GenerateGuid(), server_address_, helper_.get(),
    167                          writer_.get(), false, supported_versions_),
    168       &crypto_config_));
    169   return session_->CryptoConnect();
    170 }
    171 
    172 bool QuicClient::EncryptionBeingEstablished() {
    173   return !session_->IsEncryptionEstablished() &&
    174       session_->connection()->connected();
    175 }
    176 
    177 void QuicClient::Disconnect() {
    178   DCHECK(initialized_);
    179 
    180   if (connected()) {
    181     session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
    182   }
    183   epoll_server_.UnregisterFD(fd_);
    184   close(fd_);
    185   fd_ = -1;
    186   initialized_ = false;
    187 }
    188 
    189 void QuicClient::SendRequestsAndWaitForResponse(
    190     const CommandLine::StringVector& args) {
    191   for (size_t i = 0; i < args.size(); ++i) {
    192     BalsaHeaders headers;
    193     headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
    194     QuicSpdyClientStream* stream = CreateReliableClientStream();
    195     stream->SendRequest(headers, "", true);
    196     stream->set_visitor(this);
    197   }
    198 
    199   while (WaitForEvents()) { }
    200 }
    201 
    202 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
    203   if (!connected()) {
    204     return NULL;
    205   }
    206 
    207   return session_->CreateOutgoingDataStream();
    208 }
    209 
    210 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
    211   DCHECK(connected());
    212 
    213   while (!session_->IsClosedStream(id)) {
    214     epoll_server_.WaitForEventsAndExecuteCallbacks();
    215   }
    216 }
    217 
    218 void QuicClient::WaitForCryptoHandshakeConfirmed() {
    219   DCHECK(connected());
    220 
    221   while (!session_->IsCryptoHandshakeConfirmed()) {
    222     epoll_server_.WaitForEventsAndExecuteCallbacks();
    223   }
    224 }
    225 
    226 bool QuicClient::WaitForEvents() {
    227   DCHECK(connected());
    228 
    229   epoll_server_.WaitForEventsAndExecuteCallbacks();
    230   return session_->num_active_requests() != 0;
    231 }
    232 
    233 void QuicClient::OnEvent(int fd, EpollEvent* event) {
    234   DCHECK_EQ(fd, fd_);
    235 
    236   if (event->in_events & EPOLLIN) {
    237     while (connected() && ReadAndProcessPacket()) {
    238     }
    239   }
    240   if (connected() && (event->in_events & EPOLLOUT)) {
    241     session_->connection()->OnCanWrite();
    242   }
    243   if (event->in_events & EPOLLERR) {
    244     DLOG(INFO) << "Epollerr";
    245   }
    246 }
    247 
    248 void QuicClient::OnClose(QuicDataStream* stream) {
    249   if (!print_response_) {
    250     return;
    251   }
    252 
    253   QuicSpdyClientStream* client_stream =
    254       static_cast<QuicSpdyClientStream*>(stream);
    255   const BalsaHeaders& headers = client_stream->headers();
    256   printf("%s\n", headers.first_line().as_string().c_str());
    257   for (BalsaHeaders::const_header_lines_iterator i =
    258            headers.header_lines_begin();
    259        i != headers.header_lines_end(); ++i) {
    260     printf("%s: %s\n", i->first.as_string().c_str(),
    261            i->second.as_string().c_str());
    262   }
    263   printf("%s\n", client_stream->data().c_str());
    264 }
    265 
    266 QuicPacketCreator::Options* QuicClient::options() {
    267   if (session() == NULL) {
    268     return NULL;
    269   }
    270   return session_->options();
    271 }
    272 
    273 bool QuicClient::connected() const {
    274   return session_.get() && session_->connection() &&
    275       session_->connection()->connected();
    276 }
    277 
    278 QuicGuid QuicClient::GenerateGuid() {
    279   return QuicRandom::GetInstance()->RandUint64();
    280 }
    281 
    282 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
    283   return new QuicEpollConnectionHelper(&epoll_server_);
    284 }
    285 
    286 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
    287   return new QuicDefaultPacketWriter(fd_);
    288 }
    289 
    290 bool QuicClient::ReadAndProcessPacket() {
    291   // Allocate some extra space so we can send an error if the server goes over
    292   // the limit.
    293   char buf[2 * kMaxPacketSize];
    294 
    295   IPEndPoint server_address;
    296   IPAddressNumber client_ip;
    297 
    298   int bytes_read = QuicSocketUtils::ReadPacket(
    299       fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
    300       &client_ip, &server_address);
    301 
    302   if (bytes_read < 0) {
    303     return false;
    304   }
    305 
    306   QuicEncryptedPacket packet(buf, bytes_read, false);
    307   QuicGuid our_guid = session_->connection()->guid();
    308   QuicGuid packet_guid;
    309 
    310   if (!QuicFramer::ReadGuidFromPacket(packet, &packet_guid)) {
    311     DLOG(INFO) << "Could not read GUID from packet";
    312     return true;
    313   }
    314   if (packet_guid != our_guid) {
    315     DLOG(INFO) << "Ignoring packet from unexpected GUID: "
    316                << packet_guid << " instead of " << our_guid;
    317     return true;
    318   }
    319 
    320   IPEndPoint client_address(client_ip, client_address_.port());
    321   session_->connection()->ProcessUdpPacket(
    322       client_address, server_address, packet);
    323   return true;
    324 }
    325 
    326 }  // namespace tools
    327 }  // namespace net
    328