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