| OLD | NEW |
| (Empty) |
| 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/quic/quic_server_id.h" | |
| 20 #include "net/tools/balsa/balsa_headers.h" | |
| 21 #include "net/tools/epoll_server/epoll_server.h" | |
| 22 #include "net/tools/quic/quic_epoll_connection_helper.h" | |
| 23 #include "net/tools/quic/quic_socket_utils.h" | |
| 24 #include "net/tools/quic/quic_spdy_client_stream.h" | |
| 25 | |
| 26 #ifndef SO_RXQ_OVFL | |
| 27 #define SO_RXQ_OVFL 40 | |
| 28 #endif | |
| 29 | |
| 30 using std::string; | |
| 31 | |
| 32 namespace net { | |
| 33 namespace tools { | |
| 34 | |
| 35 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; | |
| 36 | |
| 37 QuicClient::QuicClient(IPEndPoint server_address, | |
| 38 const QuicServerId& server_id, | |
| 39 const QuicVersionVector& supported_versions, | |
| 40 EpollServer* epoll_server) | |
| 41 : server_address_(server_address), | |
| 42 server_id_(server_id), | |
| 43 local_port_(0), | |
| 44 epoll_server_(epoll_server), | |
| 45 fd_(-1), | |
| 46 helper_(CreateQuicConnectionHelper()), | |
| 47 initialized_(false), | |
| 48 packets_dropped_(0), | |
| 49 overflow_supported_(false), | |
| 50 supported_versions_(supported_versions), | |
| 51 store_response_(false), | |
| 52 latest_response_code_(-1) { | |
| 53 } | |
| 54 | |
| 55 QuicClient::QuicClient(IPEndPoint server_address, | |
| 56 const QuicServerId& server_id, | |
| 57 const QuicVersionVector& supported_versions, | |
| 58 const QuicConfig& config, | |
| 59 EpollServer* epoll_server) | |
| 60 : server_address_(server_address), | |
| 61 server_id_(server_id), | |
| 62 config_(config), | |
| 63 local_port_(0), | |
| 64 epoll_server_(epoll_server), | |
| 65 fd_(-1), | |
| 66 helper_(CreateQuicConnectionHelper()), | |
| 67 initialized_(false), | |
| 68 packets_dropped_(0), | |
| 69 overflow_supported_(false), | |
| 70 supported_versions_(supported_versions), | |
| 71 store_response_(false), | |
| 72 latest_response_code_(-1) { | |
| 73 } | |
| 74 | |
| 75 QuicClient::~QuicClient() { | |
| 76 if (connected()) { | |
| 77 session()->connection()->SendConnectionClosePacket( | |
| 78 QUIC_PEER_GOING_AWAY, ""); | |
| 79 } | |
| 80 | |
| 81 CleanUpUDPSocket(); | |
| 82 } | |
| 83 | |
| 84 bool QuicClient::Initialize() { | |
| 85 DCHECK(!initialized_); | |
| 86 | |
| 87 // If an initial flow control window has not explicitly been set, then use the | |
| 88 // same value that Chrome uses: 10 Mb. | |
| 89 const uint32 kInitialFlowControlWindow = 10 * 1024 * 1024; // 10 Mb | |
| 90 if (config_.GetInitialStreamFlowControlWindowToSend() == | |
| 91 kMinimumFlowControlSendWindow) { | |
| 92 config_.SetInitialStreamFlowControlWindowToSend(kInitialFlowControlWindow); | |
| 93 } | |
| 94 if (config_.GetInitialSessionFlowControlWindowToSend() == | |
| 95 kMinimumFlowControlSendWindow) { | |
| 96 config_.SetInitialSessionFlowControlWindowToSend(kInitialFlowControlWindow); | |
| 97 } | |
| 98 | |
| 99 epoll_server_->set_timeout_in_us(50 * 1000); | |
| 100 | |
| 101 if (!CreateUDPSocket()) { | |
| 102 return false; | |
| 103 } | |
| 104 | |
| 105 epoll_server_->RegisterFD(fd_, this, kEpollFlags); | |
| 106 initialized_ = true; | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory( | |
| 111 QuicPacketWriter* writer) | |
| 112 : writer_(writer) {} | |
| 113 | |
| 114 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {} | |
| 115 | |
| 116 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create( | |
| 117 QuicConnection* /*connection*/) const { | |
| 118 return writer_; | |
| 119 } | |
| 120 | |
| 121 | |
| 122 bool QuicClient::CreateUDPSocket() { | |
| 123 int address_family = server_address_.GetSockAddrFamily(); | |
| 124 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); | |
| 125 if (fd_ < 0) { | |
| 126 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno); | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 130 int get_overflow = 1; | |
| 131 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, | |
| 132 sizeof(get_overflow)); | |
| 133 if (rc < 0) { | |
| 134 DLOG(WARNING) << "Socket overflow detection not supported"; | |
| 135 } else { | |
| 136 overflow_supported_ = true; | |
| 137 } | |
| 138 | |
| 139 if (!QuicSocketUtils::SetReceiveBufferSize(fd_, | |
| 140 kDefaultSocketReceiveBuffer)) { | |
| 141 return false; | |
| 142 } | |
| 143 | |
| 144 if (!QuicSocketUtils::SetSendBufferSize(fd_, kDefaultSocketReceiveBuffer)) { | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family); | |
| 149 if (rc < 0) { | |
| 150 LOG(ERROR) << "IP detection not supported" << strerror(errno); | |
| 151 return false; | |
| 152 } | |
| 153 | |
| 154 if (bind_to_address_.size() != 0) { | |
| 155 client_address_ = IPEndPoint(bind_to_address_, local_port_); | |
| 156 } else if (address_family == AF_INET) { | |
| 157 IPAddressNumber any4; | |
| 158 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4)); | |
| 159 client_address_ = IPEndPoint(any4, local_port_); | |
| 160 } else { | |
| 161 IPAddressNumber any6; | |
| 162 CHECK(net::ParseIPLiteralToNumber("::", &any6)); | |
| 163 client_address_ = IPEndPoint(any6, local_port_); | |
| 164 } | |
| 165 | |
| 166 sockaddr_storage raw_addr; | |
| 167 socklen_t raw_addr_len = sizeof(raw_addr); | |
| 168 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr), | |
| 169 &raw_addr_len)); | |
| 170 rc = bind(fd_, | |
| 171 reinterpret_cast<const sockaddr*>(&raw_addr), | |
| 172 sizeof(raw_addr)); | |
| 173 if (rc < 0) { | |
| 174 LOG(ERROR) << "Bind failed: " << strerror(errno); | |
| 175 return false; | |
| 176 } | |
| 177 | |
| 178 SockaddrStorage storage; | |
| 179 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 || | |
| 180 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) { | |
| 181 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno); | |
| 182 } | |
| 183 | |
| 184 return true; | |
| 185 } | |
| 186 | |
| 187 bool QuicClient::Connect() { | |
| 188 StartConnect(); | |
| 189 while (EncryptionBeingEstablished()) { | |
| 190 WaitForEvents(); | |
| 191 } | |
| 192 return session_->connection()->connected(); | |
| 193 } | |
| 194 | |
| 195 void QuicClient::StartConnect() { | |
| 196 DCHECK(initialized_); | |
| 197 DCHECK(!connected()); | |
| 198 | |
| 199 QuicPacketWriter* writer = CreateQuicPacketWriter(); | |
| 200 | |
| 201 DummyPacketWriterFactory factory(writer); | |
| 202 | |
| 203 session_.reset(new QuicClientSession( | |
| 204 config_, | |
| 205 new QuicConnection(GenerateConnectionId(), | |
| 206 server_address_, | |
| 207 helper_.get(), | |
| 208 factory, | |
| 209 /* owns_writer= */ false, | |
| 210 /* is_server= */ false, | |
| 211 server_id_.is_https(), | |
| 212 supported_versions_))); | |
| 213 | |
| 214 // Reset |writer_| after |session_| so that the old writer outlives the old | |
| 215 // session. | |
| 216 if (writer_.get() != writer) { | |
| 217 writer_.reset(writer); | |
| 218 } | |
| 219 session_->InitializeSession(server_id_, &crypto_config_); | |
| 220 session_->CryptoConnect(); | |
| 221 } | |
| 222 | |
| 223 bool QuicClient::EncryptionBeingEstablished() { | |
| 224 return !session_->IsEncryptionEstablished() && | |
| 225 session_->connection()->connected(); | |
| 226 } | |
| 227 | |
| 228 void QuicClient::Disconnect() { | |
| 229 DCHECK(initialized_); | |
| 230 | |
| 231 if (connected()) { | |
| 232 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); | |
| 233 } | |
| 234 | |
| 235 CleanUpUDPSocket(); | |
| 236 | |
| 237 initialized_ = false; | |
| 238 } | |
| 239 | |
| 240 void QuicClient::CleanUpUDPSocket() { | |
| 241 if (fd_ > -1) { | |
| 242 epoll_server_->UnregisterFD(fd_); | |
| 243 close(fd_); | |
| 244 fd_ = -1; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 void QuicClient::SendRequest(const BalsaHeaders& headers, | |
| 249 StringPiece body, | |
| 250 bool fin) { | |
| 251 QuicSpdyClientStream* stream = CreateReliableClientStream(); | |
| 252 if (stream == nullptr) { | |
| 253 LOG(DFATAL) << "stream creation failed!"; | |
| 254 return; | |
| 255 } | |
| 256 stream->SendRequest(headers, body, fin); | |
| 257 stream->set_visitor(this); | |
| 258 } | |
| 259 | |
| 260 void QuicClient::SendRequestAndWaitForResponse(const BalsaHeaders& headers, | |
| 261 StringPiece body, | |
| 262 bool fin) { | |
| 263 SendRequest(headers, "", true); | |
| 264 while (WaitForEvents()) { | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 void QuicClient::SendRequestsAndWaitForResponse( | |
| 269 const base::CommandLine::StringVector& args) { | |
| 270 for (size_t i = 0; i < args.size(); ++i) { | |
| 271 BalsaHeaders headers; | |
| 272 headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1"); | |
| 273 SendRequest(headers, "", true); | |
| 274 } | |
| 275 while (WaitForEvents()) {} | |
| 276 } | |
| 277 | |
| 278 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() { | |
| 279 if (!connected()) { | |
| 280 return nullptr; | |
| 281 } | |
| 282 | |
| 283 return session_->CreateOutgoingDataStream(); | |
| 284 } | |
| 285 | |
| 286 void QuicClient::WaitForStreamToClose(QuicStreamId id) { | |
| 287 DCHECK(connected()); | |
| 288 | |
| 289 while (connected() && !session_->IsClosedStream(id)) { | |
| 290 epoll_server_->WaitForEventsAndExecuteCallbacks(); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 void QuicClient::WaitForCryptoHandshakeConfirmed() { | |
| 295 DCHECK(connected()); | |
| 296 | |
| 297 while (connected() && !session_->IsCryptoHandshakeConfirmed()) { | |
| 298 epoll_server_->WaitForEventsAndExecuteCallbacks(); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 bool QuicClient::WaitForEvents() { | |
| 303 DCHECK(connected()); | |
| 304 | |
| 305 epoll_server_->WaitForEventsAndExecuteCallbacks(); | |
| 306 return session_->num_active_requests() != 0; | |
| 307 } | |
| 308 | |
| 309 void QuicClient::OnEvent(int fd, EpollEvent* event) { | |
| 310 DCHECK_EQ(fd, fd_); | |
| 311 | |
| 312 if (event->in_events & EPOLLIN) { | |
| 313 while (connected() && ReadAndProcessPacket()) { | |
| 314 } | |
| 315 } | |
| 316 if (connected() && (event->in_events & EPOLLOUT)) { | |
| 317 writer_->SetWritable(); | |
| 318 session_->connection()->OnCanWrite(); | |
| 319 } | |
| 320 if (event->in_events & EPOLLERR) { | |
| 321 DVLOG(1) << "Epollerr"; | |
| 322 } | |
| 323 } | |
| 324 | |
| 325 void QuicClient::OnClose(QuicDataStream* stream) { | |
| 326 QuicSpdyClientStream* client_stream = | |
| 327 static_cast<QuicSpdyClientStream*>(stream); | |
| 328 if (response_listener_.get() != nullptr) { | |
| 329 response_listener_->OnCompleteResponse( | |
| 330 stream->id(), client_stream->headers(), client_stream->data()); | |
| 331 } | |
| 332 | |
| 333 // Store response headers and body. | |
| 334 if (store_response_) { | |
| 335 latest_response_code_ = client_stream->headers().parsed_response_code(); | |
| 336 client_stream->headers().DumpHeadersToString(&latest_response_headers_); | |
| 337 latest_response_body_ = client_stream->data(); | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 bool QuicClient::connected() const { | |
| 342 return session_.get() && session_->connection() && | |
| 343 session_->connection()->connected(); | |
| 344 } | |
| 345 | |
| 346 bool QuicClient::goaway_received() const { | |
| 347 return session_ != nullptr && session_->goaway_received(); | |
| 348 } | |
| 349 | |
| 350 size_t QuicClient::latest_response_code() const { | |
| 351 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | |
| 352 return latest_response_code_; | |
| 353 } | |
| 354 | |
| 355 const string& QuicClient::latest_response_headers() const { | |
| 356 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | |
| 357 return latest_response_headers_; | |
| 358 } | |
| 359 | |
| 360 const string& QuicClient::latest_response_body() const { | |
| 361 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | |
| 362 return latest_response_body_; | |
| 363 } | |
| 364 | |
| 365 QuicConnectionId QuicClient::GenerateConnectionId() { | |
| 366 return QuicRandom::GetInstance()->RandUint64(); | |
| 367 } | |
| 368 | |
| 369 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() { | |
| 370 return new QuicEpollConnectionHelper(epoll_server_); | |
| 371 } | |
| 372 | |
| 373 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() { | |
| 374 return new QuicDefaultPacketWriter(fd_); | |
| 375 } | |
| 376 | |
| 377 int QuicClient::ReadPacket(char* buffer, | |
| 378 int buffer_len, | |
| 379 IPEndPoint* server_address, | |
| 380 IPAddressNumber* client_ip) { | |
| 381 return QuicSocketUtils::ReadPacket( | |
| 382 fd_, buffer, buffer_len, | |
| 383 overflow_supported_ ? &packets_dropped_ : nullptr, client_ip, | |
| 384 server_address); | |
| 385 } | |
| 386 | |
| 387 bool QuicClient::ReadAndProcessPacket() { | |
| 388 // Allocate some extra space so we can send an error if the server goes over | |
| 389 // the limit. | |
| 390 char buf[2 * kMaxPacketSize]; | |
| 391 | |
| 392 IPEndPoint server_address; | |
| 393 IPAddressNumber client_ip; | |
| 394 | |
| 395 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip); | |
| 396 | |
| 397 if (bytes_read < 0) { | |
| 398 return false; | |
| 399 } | |
| 400 | |
| 401 QuicEncryptedPacket packet(buf, bytes_read, false); | |
| 402 | |
| 403 IPEndPoint client_address(client_ip, client_address_.port()); | |
| 404 session_->connection()->ProcessUdpPacket( | |
| 405 client_address, server_address, packet); | |
| 406 return true; | |
| 407 } | |
| 408 | |
| 409 } // namespace tools | |
| 410 } // namespace net | |
| OLD | NEW |