Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: net/tools/quic/quic_client.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/tools/quic/quic_client.h ('k') | net/tools/quic/quic_client_bin.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « net/tools/quic/quic_client.h ('k') | net/tools/quic/quic_client_bin.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698