Revert "make EpollServer with with Posix poll(), take 2."
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blobaed51f556510eb2a9b17fec3b0562f0541d52f89
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.
5 #include "net/tools/quic/quic_client.h"
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>
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 #include "net/tools/quic/spdy_utils.h"
27 #ifndef SO_RXQ_OVFL
28 #define SO_RXQ_OVFL 40
29 #endif
31 using std::string;
32 using std::vector;
34 namespace net {
35 namespace tools {
37 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
39 QuicClient::QuicClient(IPEndPoint server_address,
40 const QuicServerId& server_id,
41 const QuicVersionVector& supported_versions,
42 EpollServer* epoll_server)
43 : server_address_(server_address),
44 server_id_(server_id),
45 local_port_(0),
46 epoll_server_(epoll_server),
47 fd_(-1),
48 helper_(CreateQuicConnectionHelper()),
49 initialized_(false),
50 packets_dropped_(0),
51 overflow_supported_(false),
52 supported_versions_(supported_versions),
53 store_response_(false),
54 latest_response_code_(-1) {
57 QuicClient::QuicClient(IPEndPoint server_address,
58 const QuicServerId& server_id,
59 const QuicVersionVector& supported_versions,
60 const QuicConfig& config,
61 EpollServer* epoll_server)
62 : server_address_(server_address),
63 server_id_(server_id),
64 config_(config),
65 local_port_(0),
66 epoll_server_(epoll_server),
67 fd_(-1),
68 helper_(CreateQuicConnectionHelper()),
69 initialized_(false),
70 packets_dropped_(0),
71 overflow_supported_(false),
72 supported_versions_(supported_versions),
73 store_response_(false),
74 latest_response_code_(-1) {
77 QuicClient::~QuicClient() {
78 if (connected()) {
79 session()->connection()->SendConnectionClosePacket(
80 QUIC_PEER_GOING_AWAY, "");
83 CleanUpUDPSocket();
86 bool QuicClient::Initialize() {
87 DCHECK(!initialized_);
89 // If an initial flow control window has not explicitly been set, then use the
90 // same value that Chrome uses: 10 Mb.
91 const uint32 kInitialFlowControlWindow = 10 * 1024 * 1024; // 10 Mb
92 if (config_.GetInitialStreamFlowControlWindowToSend() ==
93 kMinimumFlowControlSendWindow) {
94 config_.SetInitialStreamFlowControlWindowToSend(kInitialFlowControlWindow);
96 if (config_.GetInitialSessionFlowControlWindowToSend() ==
97 kMinimumFlowControlSendWindow) {
98 config_.SetInitialSessionFlowControlWindowToSend(kInitialFlowControlWindow);
101 epoll_server_->set_timeout_in_us(50 * 1000);
103 if (!CreateUDPSocket()) {
104 return false;
107 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
108 initialized_ = true;
109 return true;
112 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
113 QuicPacketWriter* writer)
114 : writer_(writer) {}
116 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
118 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
119 QuicConnection* /*connection*/) const {
120 return writer_;
124 bool QuicClient::CreateUDPSocket() {
125 int address_family = server_address_.GetSockAddrFamily();
126 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
127 if (fd_ < 0) {
128 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
129 return false;
132 int get_overflow = 1;
133 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
134 sizeof(get_overflow));
135 if (rc < 0) {
136 DLOG(WARNING) << "Socket overflow detection not supported";
137 } else {
138 overflow_supported_ = true;
141 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
142 kDefaultSocketReceiveBuffer)) {
143 return false;
146 if (!QuicSocketUtils::SetSendBufferSize(fd_, kDefaultSocketReceiveBuffer)) {
147 return false;
150 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
151 if (rc < 0) {
152 LOG(ERROR) << "IP detection not supported" << strerror(errno);
153 return false;
156 if (bind_to_address_.size() != 0) {
157 client_address_ = IPEndPoint(bind_to_address_, local_port_);
158 } else if (address_family == AF_INET) {
159 IPAddressNumber any4;
160 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
161 client_address_ = IPEndPoint(any4, local_port_);
162 } else {
163 IPAddressNumber any6;
164 CHECK(net::ParseIPLiteralToNumber("::", &any6));
165 client_address_ = IPEndPoint(any6, local_port_);
168 sockaddr_storage raw_addr;
169 socklen_t raw_addr_len = sizeof(raw_addr);
170 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
171 &raw_addr_len));
172 rc = bind(fd_,
173 reinterpret_cast<const sockaddr*>(&raw_addr),
174 sizeof(raw_addr));
175 if (rc < 0) {
176 LOG(ERROR) << "Bind failed: " << strerror(errno);
177 return false;
180 SockaddrStorage storage;
181 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
182 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
183 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
186 return true;
189 bool QuicClient::Connect() {
190 StartConnect();
191 while (EncryptionBeingEstablished()) {
192 WaitForEvents();
194 return session_->connection()->connected();
197 void QuicClient::StartConnect() {
198 DCHECK(initialized_);
199 DCHECK(!connected());
201 QuicPacketWriter* writer = CreateQuicPacketWriter();
203 DummyPacketWriterFactory factory(writer);
205 session_.reset(new QuicClientSession(
206 config_,
207 new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
208 factory,
209 /* owns_writer= */ false, Perspective::IS_CLIENT,
210 server_id_.is_https(), supported_versions_)));
212 // Reset |writer_| after |session_| so that the old writer outlives the old
213 // session.
214 if (writer_.get() != writer) {
215 writer_.reset(writer);
217 session_->InitializeSession(server_id_, &crypto_config_);
218 session_->CryptoConnect();
221 bool QuicClient::EncryptionBeingEstablished() {
222 return !session_->IsEncryptionEstablished() &&
223 session_->connection()->connected();
226 void QuicClient::Disconnect() {
227 DCHECK(initialized_);
229 if (connected()) {
230 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
233 CleanUpUDPSocket();
235 initialized_ = false;
238 void QuicClient::CleanUpUDPSocket() {
239 if (fd_ > -1) {
240 epoll_server_->UnregisterFD(fd_);
241 close(fd_);
242 fd_ = -1;
246 void QuicClient::SendRequest(const BalsaHeaders& headers,
247 StringPiece body,
248 bool fin) {
249 QuicSpdyClientStream* stream = CreateReliableClientStream();
250 if (stream == nullptr) {
251 LOG(DFATAL) << "stream creation failed!";
252 return;
254 stream->SendRequest(
255 SpdyUtils::RequestHeadersToSpdyHeaders(headers), body, fin);
256 stream->set_visitor(this);
259 void QuicClient::SendRequestAndWaitForResponse(
260 const BalsaHeaders& headers,
261 StringPiece body,
262 bool fin) {
263 SendRequest(headers, body, fin);
264 while (WaitForEvents()) {}
267 void QuicClient::SendRequestsAndWaitForResponse(
268 const vector<string>& url_list) {
269 for (size_t i = 0; i < url_list.size(); ++i) {
270 BalsaHeaders headers;
271 headers.SetRequestFirstlineFromStringPieces("GET", url_list[i], "HTTP/1.1");
272 SendRequest(headers, "", true);
274 while (WaitForEvents()) {}
277 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
278 if (!connected()) {
279 return nullptr;
282 return session_->CreateOutgoingDataStream();
285 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
286 DCHECK(connected());
288 while (connected() && !session_->IsClosedStream(id)) {
289 WaitForEvents();
293 void QuicClient::WaitForCryptoHandshakeConfirmed() {
294 DCHECK(connected());
296 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
297 WaitForEvents();
301 bool QuicClient::WaitForEvents() {
302 DCHECK(connected());
304 epoll_server_->WaitForEventsAndExecuteCallbacks();
305 return session_->num_active_requests() != 0;
308 void QuicClient::OnEvent(int fd, EpollEvent* event) {
309 DCHECK_EQ(fd, fd_);
311 if (event->in_events & EPOLLIN) {
312 while (connected() && ReadAndProcessPacket()) {
315 if (connected() && (event->in_events & EPOLLOUT)) {
316 writer_->SetWritable();
317 session_->connection()->OnCanWrite();
319 if (event->in_events & EPOLLERR) {
320 DVLOG(1) << "Epollerr";
324 void QuicClient::OnClose(QuicDataStream* stream) {
325 QuicSpdyClientStream* client_stream =
326 static_cast<QuicSpdyClientStream*>(stream);
327 BalsaHeaders headers;
328 SpdyUtils::FillBalsaResponseHeaders(client_stream->headers(), &headers);
330 if (response_listener_.get() != nullptr) {
331 response_listener_->OnCompleteResponse(
332 stream->id(), headers, client_stream->data());
335 // Store response headers and body.
336 if (store_response_) {
337 latest_response_code_ = headers.parsed_response_code();
338 headers.DumpHeadersToString(&latest_response_headers_);
339 latest_response_body_ = client_stream->data();
343 bool QuicClient::connected() const {
344 return session_.get() && session_->connection() &&
345 session_->connection()->connected();
348 bool QuicClient::goaway_received() const {
349 return session_ != nullptr && session_->goaway_received();
352 size_t QuicClient::latest_response_code() const {
353 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
354 return latest_response_code_;
357 const string& QuicClient::latest_response_headers() const {
358 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
359 return latest_response_headers_;
362 const string& QuicClient::latest_response_body() const {
363 LOG_IF(DFATAL, !store_response_) << "Response not stored!";
364 return latest_response_body_;
367 QuicConnectionId QuicClient::GenerateConnectionId() {
368 return QuicRandom::GetInstance()->RandUint64();
371 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
372 return new QuicEpollConnectionHelper(epoll_server_);
375 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
376 return new QuicDefaultPacketWriter(fd_);
379 int QuicClient::ReadPacket(char* buffer,
380 int buffer_len,
381 IPEndPoint* server_address,
382 IPAddressNumber* client_ip) {
383 return QuicSocketUtils::ReadPacket(
384 fd_, buffer, buffer_len,
385 overflow_supported_ ? &packets_dropped_ : nullptr, client_ip,
386 server_address);
389 bool QuicClient::ReadAndProcessPacket() {
390 // Allocate some extra space so we can send an error if the server goes over
391 // the limit.
392 char buf[2 * kMaxPacketSize];
394 IPEndPoint server_address;
395 IPAddressNumber client_ip;
397 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
399 if (bytes_read < 0) {
400 return false;
403 QuicEncryptedPacket packet(buf, bytes_read, false);
405 IPEndPoint client_address(client_ip, client_address_.port());
406 session_->connection()->ProcessUdpPacket(
407 client_address, server_address, packet);
408 return true;
411 } // namespace tools
412 } // namespace net