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