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