Initialize UserMetricsRecorder on Windows Ash and Ozone
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blob6264be0471b38445151fd9ceb2b2fc7c5622da5a
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/congestion_control/tcp_receiver.h"
16 #include "net/quic/crypto/quic_random.h"
17 #include "net/quic/quic_connection.h"
18 #include "net/quic/quic_data_reader.h"
19 #include "net/quic/quic_protocol.h"
20 #include "net/quic/quic_server_id.h"
21 #include "net/tools/balsa/balsa_headers.h"
22 #include "net/tools/epoll_server/epoll_server.h"
23 #include "net/tools/quic/quic_epoll_connection_helper.h"
24 #include "net/tools/quic/quic_socket_utils.h"
25 #include "net/tools/quic/quic_spdy_client_stream.h"
27 #ifndef SO_RXQ_OVFL
28 #define SO_RXQ_OVFL 40
29 #endif
31 namespace net {
32 namespace tools {
34 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
36 QuicClient::QuicClient(IPEndPoint server_address,
37 const QuicServerId& server_id,
38 const QuicVersionVector& supported_versions,
39 bool print_response,
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 print_response_(print_response) {
54 QuicClient::QuicClient(IPEndPoint server_address,
55 const QuicServerId& server_id,
56 const QuicVersionVector& supported_versions,
57 bool print_response,
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 print_response_(print_response) {
74 QuicClient::~QuicClient() {
75 if (connected()) {
76 session()->connection()->SendConnectionClosePacket(
77 QUIC_PEER_GOING_AWAY, "");
79 if (fd_ > 0) {
80 epoll_server_->UnregisterFD(fd_);
84 bool QuicClient::Initialize() {
85 DCHECK(!initialized_);
87 epoll_server_->set_timeout_in_us(50 * 1000);
89 if (!CreateUDPSocket()) {
90 return false;
93 epoll_server_->RegisterFD(fd_, this, kEpollFlags);
94 initialized_ = true;
95 return true;
98 QuicClient::DummyPacketWriterFactory::DummyPacketWriterFactory(
99 QuicPacketWriter* writer)
100 : writer_(writer) {}
102 QuicClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {}
104 QuicPacketWriter* QuicClient::DummyPacketWriterFactory::Create(
105 QuicConnection* /*connection*/) const {
106 return writer_;
110 bool QuicClient::CreateUDPSocket() {
111 int address_family = server_address_.GetSockAddrFamily();
112 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
113 if (fd_ < 0) {
114 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
115 return false;
118 int get_overflow = 1;
119 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
120 sizeof(get_overflow));
121 if (rc < 0) {
122 DLOG(WARNING) << "Socket overflow detection not supported";
123 } else {
124 overflow_supported_ = true;
127 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
128 TcpReceiver::kReceiveWindowTCP)) {
129 return false;
132 if (!QuicSocketUtils::SetSendBufferSize(fd_,
133 TcpReceiver::kReceiveWindowTCP)) {
134 return false;
137 rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
138 if (rc < 0) {
139 LOG(ERROR) << "IP detection not supported" << strerror(errno);
140 return false;
143 if (bind_to_address_.size() != 0) {
144 client_address_ = IPEndPoint(bind_to_address_, local_port_);
145 } else if (address_family == AF_INET) {
146 IPAddressNumber any4;
147 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
148 client_address_ = IPEndPoint(any4, local_port_);
149 } else {
150 IPAddressNumber any6;
151 CHECK(net::ParseIPLiteralToNumber("::", &any6));
152 client_address_ = IPEndPoint(any6, local_port_);
155 sockaddr_storage raw_addr;
156 socklen_t raw_addr_len = sizeof(raw_addr);
157 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
158 &raw_addr_len));
159 rc = bind(fd_,
160 reinterpret_cast<const sockaddr*>(&raw_addr),
161 sizeof(raw_addr));
162 if (rc < 0) {
163 LOG(ERROR) << "Bind failed: " << strerror(errno);
164 return false;
167 SockaddrStorage storage;
168 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
169 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
170 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
173 return true;
176 bool QuicClient::Connect() {
177 if (!StartConnect()) {
178 return false;
180 while (EncryptionBeingEstablished()) {
181 WaitForEvents();
183 return session_->connection()->connected();
186 bool QuicClient::StartConnect() {
187 DCHECK(initialized_);
188 DCHECK(!connected());
190 QuicPacketWriter* writer = CreateQuicPacketWriter();
192 DummyPacketWriterFactory factory(writer);
194 session_.reset(new QuicClientSession(
195 config_,
196 new QuicConnection(GenerateConnectionId(),
197 server_address_,
198 helper_.get(),
199 factory,
200 /* owns_writer= */ false,
201 /* is_server= */ false,
202 server_id_.is_https(),
203 supported_versions_)));
205 // Reset |writer_| after |session_| so that the old writer outlives the old
206 // session.
207 if (writer_.get() != writer) {
208 writer_.reset(writer);
210 session_->InitializeSession(server_id_, &crypto_config_);
211 return session_->CryptoConnect();
214 bool QuicClient::EncryptionBeingEstablished() {
215 return !session_->IsEncryptionEstablished() &&
216 session_->connection()->connected();
219 void QuicClient::Disconnect() {
220 DCHECK(initialized_);
222 if (connected()) {
223 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
225 epoll_server_->UnregisterFD(fd_);
226 close(fd_);
227 fd_ = -1;
228 initialized_ = false;
231 void QuicClient::SendRequestsAndWaitForResponse(
232 const base::CommandLine::StringVector& args) {
233 for (size_t i = 0; i < args.size(); ++i) {
234 BalsaHeaders headers;
235 headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
236 QuicSpdyClientStream* stream = CreateReliableClientStream();
237 DCHECK(stream != nullptr);
238 if (stream == nullptr) {
239 LOG(ERROR) << "stream creation failed!";
240 break;
242 stream->SendRequest(headers, "", true);
243 stream->set_visitor(this);
246 while (WaitForEvents()) {}
249 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
250 if (!connected()) {
251 return nullptr;
254 return session_->CreateOutgoingDataStream();
257 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
258 DCHECK(connected());
260 while (connected() && !session_->IsClosedStream(id)) {
261 epoll_server_->WaitForEventsAndExecuteCallbacks();
265 void QuicClient::WaitForCryptoHandshakeConfirmed() {
266 DCHECK(connected());
268 while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
269 epoll_server_->WaitForEventsAndExecuteCallbacks();
273 bool QuicClient::WaitForEvents() {
274 DCHECK(connected());
276 epoll_server_->WaitForEventsAndExecuteCallbacks();
277 return session_->num_active_requests() != 0;
280 void QuicClient::OnEvent(int fd, EpollEvent* event) {
281 DCHECK_EQ(fd, fd_);
283 if (event->in_events & EPOLLIN) {
284 while (connected() && ReadAndProcessPacket()) {
287 if (connected() && (event->in_events & EPOLLOUT)) {
288 writer_->SetWritable();
289 session_->connection()->OnCanWrite();
291 if (event->in_events & EPOLLERR) {
292 DVLOG(1) << "Epollerr";
296 void QuicClient::OnClose(QuicDataStream* stream) {
297 QuicSpdyClientStream* client_stream =
298 static_cast<QuicSpdyClientStream*>(stream);
299 if (response_listener_.get() != nullptr) {
300 response_listener_->OnCompleteResponse(
301 stream->id(), client_stream->headers(), client_stream->data());
304 if (!print_response_) {
305 return;
308 const BalsaHeaders& headers = client_stream->headers();
309 printf("%s\n", headers.first_line().as_string().c_str());
310 for (BalsaHeaders::const_header_lines_iterator i =
311 headers.header_lines_begin();
312 i != headers.header_lines_end(); ++i) {
313 printf("%s: %s\n", i->first.as_string().c_str(),
314 i->second.as_string().c_str());
316 printf("%s\n", client_stream->data().c_str());
319 bool QuicClient::connected() const {
320 return session_.get() && session_->connection() &&
321 session_->connection()->connected();
324 bool QuicClient::goaway_received() const {
325 return session_ != nullptr && session_->goaway_received();
328 QuicConnectionId QuicClient::GenerateConnectionId() {
329 return QuicRandom::GetInstance()->RandUint64();
332 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
333 return new QuicEpollConnectionHelper(epoll_server_);
336 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
337 return new QuicDefaultPacketWriter(fd_);
340 int QuicClient::ReadPacket(char* buffer,
341 int buffer_len,
342 IPEndPoint* server_address,
343 IPAddressNumber* client_ip) {
344 return QuicSocketUtils::ReadPacket(
345 fd_, buffer, buffer_len,
346 overflow_supported_ ? &packets_dropped_ : nullptr, client_ip,
347 server_address);
350 bool QuicClient::ReadAndProcessPacket() {
351 // Allocate some extra space so we can send an error if the server goes over
352 // the limit.
353 char buf[2 * kMaxPacketSize];
355 IPEndPoint server_address;
356 IPAddressNumber client_ip;
358 int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
360 if (bytes_read < 0) {
361 return false;
364 QuicEncryptedPacket packet(buf, bytes_read, false);
366 IPEndPoint client_address(client_ip, client_address_.port());
367 session_->connection()->ProcessUdpPacket(
368 client_address, server_address, packet);
369 return true;
372 } // namespace tools
373 } // namespace net