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 |