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_server.h"
      6 
      7 #include <errno.h>
      8 #include <features.h>
      9 #include <netinet/in.h>
     10 #include <string.h>
     11 #include <sys/epoll.h>
     12 #include <sys/socket.h>
     13 
     14 #include "net/base/ip_endpoint.h"
     15 #include "net/quic/crypto/crypto_handshake.h"
     16 #include "net/quic/crypto/quic_random.h"
     17 #include "net/quic/quic_clock.h"
     18 #include "net/quic/quic_crypto_stream.h"
     19 #include "net/quic/quic_data_reader.h"
     20 #include "net/quic/quic_protocol.h"
     21 #include "net/tools/quic/quic_in_memory_cache.h"
     22 #include "net/tools/quic/quic_socket_utils.h"
     23 
     24 #define MMSG_MORE 0
     25 
     26 #ifndef SO_RXQ_OVFL
     27 #define SO_RXQ_OVFL 40
     28 #endif
     29 
     30 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
     31 const int kNumPacketsPerReadCall = 5;  // Arbitrary
     32 static const char kSourceAddressTokenSecret[] = "secret";
     33 
     34 namespace net {
     35 namespace tools {
     36 
     37 QuicServer::QuicServer()
     38     : port_(0),
     39       packets_dropped_(0),
     40       overflow_supported_(false),
     41       use_recvmmsg_(false),
     42       crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
     43   // Use hardcoded crypto parameters for now.
     44   config_.SetDefaults();
     45   Initialize();
     46 }
     47 
     48 QuicServer::QuicServer(const QuicConfig& config)
     49     : port_(0),
     50       packets_dropped_(0),
     51       overflow_supported_(false),
     52       use_recvmmsg_(false),
     53       config_(config),
     54       crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
     55   Initialize();
     56 }
     57 
     58 void QuicServer::Initialize() {
     59 #if MMSG_MORE
     60   use_recvmmsg_ = true;
     61 #endif
     62   epoll_server_.set_timeout_in_us(50 * 1000);
     63   // Initialize the in memory cache now.
     64   QuicInMemoryCache::GetInstance();
     65 
     66   QuicEpollClock clock(&epoll_server_);
     67 
     68   scoped_ptr<CryptoHandshakeMessage> scfg(
     69       crypto_config_.AddDefaultConfig(
     70           QuicRandom::GetInstance(), &clock,
     71           QuicCryptoServerConfig::ConfigOptions()));
     72 }
     73 
     74 QuicServer::~QuicServer() {
     75 }
     76 
     77 bool QuicServer::Listen(const IPEndPoint& address) {
     78   port_ = address.port();
     79   int address_family = address.GetSockAddrFamily();
     80   fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
     81   if (fd_ < 0) {
     82     LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
     83     return false;
     84   }
     85 
     86   int rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
     87 
     88   if (rc < 0) {
     89     LOG(ERROR) << "IP detection not supported" << strerror(errno);
     90     return false;
     91   }
     92 
     93   int get_overflow = 1;
     94   rc = setsockopt(
     95       fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, sizeof(get_overflow));
     96 
     97   if (rc < 0) {
     98     DLOG(WARNING) << "Socket overflow detection not supported";
     99   } else {
    100     overflow_supported_ = true;
    101   }
    102 
    103   // Enable the socket option that allows the local address to be
    104   // returned if the socket is bound to more than on address.
    105   int get_local_ip = 1;
    106   rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
    107                   &get_local_ip, sizeof(get_local_ip));
    108   if (rc == 0 && address_family == AF_INET6) {
    109     rc = setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
    110                     &get_local_ip, sizeof(get_local_ip));
    111   }
    112   if (rc != 0) {
    113     LOG(ERROR) << "Failed to set required socket options";
    114     return false;
    115   }
    116 
    117   sockaddr_storage raw_addr;
    118   socklen_t raw_addr_len = sizeof(raw_addr);
    119   CHECK(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   LOG(INFO) << "Listening on " << address.ToString();
    130   if (port_ == 0) {
    131     SockaddrStorage storage;
    132     IPEndPoint server_address;
    133     if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
    134         !server_address.FromSockAddr(storage.addr, storage.addr_len)) {
    135       LOG(ERROR) << "Unable to get self address.  Error: " << strerror(errno);
    136       return false;
    137     }
    138     port_ = server_address.port();
    139     LOG(INFO) << "Kernel assigned port is " << port_;
    140   }
    141 
    142   epoll_server_.RegisterFD(fd_, this, kEpollFlags);
    143   dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, fd_,
    144                                        &epoll_server_));
    145 
    146   return true;
    147 }
    148 
    149 void QuicServer::WaitForEvents() {
    150   epoll_server_.WaitForEventsAndExecuteCallbacks();
    151 }
    152 
    153 void QuicServer::Shutdown() {
    154   // Before we shut down the epoll server, give all active sessions a chance to
    155   // notify clients that they're closing.
    156   dispatcher_->Shutdown();
    157 }
    158 
    159 void QuicServer::OnEvent(int fd, EpollEvent* event) {
    160   DCHECK_EQ(fd, fd_);
    161   event->out_ready_mask = 0;
    162 
    163   if (event->in_events & EPOLLIN) {
    164     LOG(ERROR) << "EPOLLIN";
    165     bool read = true;
    166     while (read) {
    167         read = ReadAndDispatchSinglePacket(
    168             fd_, port_, dispatcher_.get(),
    169             overflow_supported_ ? &packets_dropped_ : NULL);
    170     }
    171   }
    172   if (event->in_events & EPOLLOUT) {
    173     bool can_write_more = dispatcher_->OnCanWrite();
    174     if (can_write_more) {
    175       event->out_ready_mask |= EPOLLOUT;
    176     }
    177   }
    178   if (event->in_events & EPOLLERR) {
    179   }
    180 }
    181 
    182 /* static */
    183 void QuicServer::MaybeDispatchPacket(QuicDispatcher* dispatcher,
    184                                      const QuicEncryptedPacket& packet,
    185                                      const IPEndPoint& server_address,
    186                                      const IPEndPoint& client_address) {
    187   QuicGuid guid;
    188   if (!QuicFramer::ReadGuidFromPacket(packet, &guid)) {
    189     return;
    190   }
    191 
    192   dispatcher->ProcessPacket(server_address, client_address, guid, packet);
    193 }
    194 
    195 bool QuicServer::ReadAndDispatchSinglePacket(int fd,
    196                                              int port,
    197                                              QuicDispatcher* dispatcher,
    198                                              int* packets_dropped) {
    199   // Allocate some extra space so we can send an error if the client goes over
    200   // the limit.
    201   char buf[2 * kMaxPacketSize];
    202 
    203   IPEndPoint client_address;
    204   IPAddressNumber server_ip;
    205   int bytes_read =
    206       QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf),
    207                                   packets_dropped,
    208                                   &server_ip, &client_address);
    209 
    210   if (bytes_read < 0) {
    211     return false;  // We failed to read.
    212   }
    213 
    214   QuicEncryptedPacket packet(buf, bytes_read, false);
    215 
    216   IPEndPoint server_address(server_ip, port);
    217   MaybeDispatchPacket(dispatcher, packet, server_address, client_address);
    218 
    219   return true;
    220 }
    221 
    222 }  // namespace tools
    223 }  // namespace net
    224