• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
26 
27 #ifndef SO_RXQ_OVFL
28 #define SO_RXQ_OVFL 40
29 #endif
30 
31 namespace net {
32 namespace tools {
33 
34 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
35 
QuicClient(IPEndPoint server_address,const QuicServerId & server_id,const QuicVersionVector & supported_versions,bool print_response,EpollServer * epoll_server)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) {
52   config_.SetDefaults();
53 }
54 
QuicClient(IPEndPoint server_address,const QuicServerId & server_id,const QuicVersionVector & supported_versions,bool print_response,const QuicConfig & config,EpollServer * epoll_server)55 QuicClient::QuicClient(IPEndPoint server_address,
56                        const QuicServerId& server_id,
57                        const QuicVersionVector& supported_versions,
58                        bool print_response,
59                        const QuicConfig& config,
60                        EpollServer* epoll_server)
61     : server_address_(server_address),
62       server_id_(server_id),
63       config_(config),
64       local_port_(0),
65       epoll_server_(epoll_server),
66       fd_(-1),
67       helper_(CreateQuicConnectionHelper()),
68       initialized_(false),
69       packets_dropped_(0),
70       overflow_supported_(false),
71       supported_versions_(supported_versions),
72       print_response_(print_response) {
73 }
74 
~QuicClient()75 QuicClient::~QuicClient() {
76   if (connected()) {
77     session()->connection()->SendConnectionClosePacket(
78         QUIC_PEER_GOING_AWAY, "");
79   }
80   if (fd_ > 0) {
81     epoll_server_->UnregisterFD(fd_);
82   }
83 }
84 
Initialize()85 bool QuicClient::Initialize() {
86   DCHECK(!initialized_);
87 
88   epoll_server_->set_timeout_in_us(50 * 1000);
89   crypto_config_.SetDefaults();
90 
91   if (!CreateUDPSocket()) {
92     return false;
93   }
94 
95   epoll_server_->RegisterFD(fd_, this, kEpollFlags);
96   initialized_ = true;
97   return true;
98 }
99 
CreateUDPSocket()100 bool QuicClient::CreateUDPSocket() {
101   int address_family = server_address_.GetSockAddrFamily();
102   fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
103   if (fd_ < 0) {
104     LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
105     return false;
106   }
107 
108   int get_overflow = 1;
109   int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
110                       sizeof(get_overflow));
111   if (rc < 0) {
112     DLOG(WARNING) << "Socket overflow detection not supported";
113   } else {
114     overflow_supported_ = true;
115   }
116 
117   if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
118                                              TcpReceiver::kReceiveWindowTCP)) {
119     return false;
120   }
121 
122   if (!QuicSocketUtils::SetSendBufferSize(fd_,
123                                           TcpReceiver::kReceiveWindowTCP)) {
124     return false;
125   }
126 
127   int get_local_ip = 1;
128   if (address_family == AF_INET) {
129     rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
130                     &get_local_ip, sizeof(get_local_ip));
131   } else {
132     rc =  setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
133                      &get_local_ip, sizeof(get_local_ip));
134   }
135 
136   if (rc < 0) {
137     LOG(ERROR) << "IP detection not supported" << strerror(errno);
138     return false;
139   }
140 
141   if (bind_to_address_.size() != 0) {
142     client_address_ = IPEndPoint(bind_to_address_, local_port_);
143   } else if (address_family == AF_INET) {
144     IPAddressNumber any4;
145     CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
146     client_address_ = IPEndPoint(any4, local_port_);
147   } else {
148     IPAddressNumber any6;
149     CHECK(net::ParseIPLiteralToNumber("::", &any6));
150     client_address_ = IPEndPoint(any6, local_port_);
151   }
152 
153   sockaddr_storage raw_addr;
154   socklen_t raw_addr_len = sizeof(raw_addr);
155   CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
156                            &raw_addr_len));
157   rc = bind(fd_,
158             reinterpret_cast<const sockaddr*>(&raw_addr),
159             sizeof(raw_addr));
160   if (rc < 0) {
161     LOG(ERROR) << "Bind failed: " << strerror(errno);
162     return false;
163   }
164 
165   SockaddrStorage storage;
166   if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
167       !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
168     LOG(ERROR) << "Unable to get self address.  Error: " << strerror(errno);
169   }
170 
171   return true;
172 }
173 
Connect()174 bool QuicClient::Connect() {
175   if (!StartConnect()) {
176     return false;
177   }
178   while (EncryptionBeingEstablished()) {
179     WaitForEvents();
180   }
181   return session_->connection()->connected();
182 }
183 
StartConnect()184 bool QuicClient::StartConnect() {
185   DCHECK(initialized_);
186   DCHECK(!connected());
187 
188   QuicPacketWriter* writer = CreateQuicPacketWriter();
189   if (writer_.get() != writer) {
190     writer_.reset(writer);
191   }
192 
193   session_.reset(new QuicClientSession(
194       server_id_,
195       config_,
196       new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
197                          writer_.get(), false, supported_versions_),
198       &crypto_config_));
199   return session_->CryptoConnect();
200 }
201 
EncryptionBeingEstablished()202 bool QuicClient::EncryptionBeingEstablished() {
203   return !session_->IsEncryptionEstablished() &&
204       session_->connection()->connected();
205 }
206 
Disconnect()207 void QuicClient::Disconnect() {
208   DCHECK(initialized_);
209 
210   if (connected()) {
211     session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
212   }
213   epoll_server_->UnregisterFD(fd_);
214   close(fd_);
215   fd_ = -1;
216   initialized_ = false;
217 }
218 
SendRequestsAndWaitForResponse(const base::CommandLine::StringVector & args)219 void QuicClient::SendRequestsAndWaitForResponse(
220     const base::CommandLine::StringVector& args) {
221   for (size_t i = 0; i < args.size(); ++i) {
222     BalsaHeaders headers;
223     headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
224     QuicSpdyClientStream* stream = CreateReliableClientStream();
225     DCHECK(stream != NULL);
226     stream->SendRequest(headers, "", true);
227     stream->set_visitor(this);
228   }
229 
230   while (WaitForEvents()) {}
231 }
232 
CreateReliableClientStream()233 QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
234   if (!connected()) {
235     return NULL;
236   }
237 
238   return session_->CreateOutgoingDataStream();
239 }
240 
WaitForStreamToClose(QuicStreamId id)241 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
242   DCHECK(connected());
243 
244   while (connected() && !session_->IsClosedStream(id)) {
245     epoll_server_->WaitForEventsAndExecuteCallbacks();
246   }
247 }
248 
WaitForCryptoHandshakeConfirmed()249 void QuicClient::WaitForCryptoHandshakeConfirmed() {
250   DCHECK(connected());
251 
252   while (connected() && !session_->IsCryptoHandshakeConfirmed()) {
253     epoll_server_->WaitForEventsAndExecuteCallbacks();
254   }
255 }
256 
WaitForEvents()257 bool QuicClient::WaitForEvents() {
258   DCHECK(connected());
259 
260   epoll_server_->WaitForEventsAndExecuteCallbacks();
261   return session_->num_active_requests() != 0;
262 }
263 
OnEvent(int fd,EpollEvent * event)264 void QuicClient::OnEvent(int fd, EpollEvent* event) {
265   DCHECK_EQ(fd, fd_);
266 
267   if (event->in_events & EPOLLIN) {
268     while (connected() && ReadAndProcessPacket()) {
269     }
270   }
271   if (connected() && (event->in_events & EPOLLOUT)) {
272     writer_->SetWritable();
273     session_->connection()->OnCanWrite();
274   }
275   if (event->in_events & EPOLLERR) {
276     DVLOG(1) << "Epollerr";
277   }
278 }
279 
OnClose(QuicDataStream * stream)280 void QuicClient::OnClose(QuicDataStream* stream) {
281   QuicSpdyClientStream* client_stream =
282       static_cast<QuicSpdyClientStream*>(stream);
283   if (response_listener_.get() != NULL) {
284     response_listener_->OnCompleteResponse(
285         stream->id(), client_stream->headers(), client_stream->data());
286   }
287 
288   if (!print_response_) {
289     return;
290   }
291 
292   const BalsaHeaders& headers = client_stream->headers();
293   printf("%s\n", headers.first_line().as_string().c_str());
294   for (BalsaHeaders::const_header_lines_iterator i =
295            headers.header_lines_begin();
296        i != headers.header_lines_end(); ++i) {
297     printf("%s: %s\n", i->first.as_string().c_str(),
298            i->second.as_string().c_str());
299   }
300   printf("%s\n", client_stream->data().c_str());
301 }
302 
connected() const303 bool QuicClient::connected() const {
304   return session_.get() && session_->connection() &&
305       session_->connection()->connected();
306 }
307 
GenerateConnectionId()308 QuicConnectionId QuicClient::GenerateConnectionId() {
309   return QuicRandom::GetInstance()->RandUint64();
310 }
311 
CreateQuicConnectionHelper()312 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
313   return new QuicEpollConnectionHelper(epoll_server_);
314 }
315 
CreateQuicPacketWriter()316 QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
317   return new QuicDefaultPacketWriter(fd_);
318 }
319 
ReadPacket(char * buffer,int buffer_len,IPEndPoint * server_address,IPAddressNumber * client_ip)320 int QuicClient::ReadPacket(char* buffer,
321                            int buffer_len,
322                            IPEndPoint* server_address,
323                            IPAddressNumber* client_ip) {
324   return QuicSocketUtils::ReadPacket(
325       fd_, buffer, buffer_len, overflow_supported_ ? &packets_dropped_ : NULL,
326       client_ip, server_address);
327 }
328 
ReadAndProcessPacket()329 bool QuicClient::ReadAndProcessPacket() {
330   // Allocate some extra space so we can send an error if the server goes over
331   // the limit.
332   char buf[2 * kMaxPacketSize];
333 
334   IPEndPoint server_address;
335   IPAddressNumber client_ip;
336 
337   int bytes_read = ReadPacket(buf, arraysize(buf), &server_address, &client_ip);
338 
339   if (bytes_read < 0) {
340     return false;
341   }
342 
343   QuicEncryptedPacket packet(buf, bytes_read, false);
344 
345   IPEndPoint client_address(client_ip, client_address_.port());
346   session_->connection()->ProcessUdpPacket(
347       client_address, server_address, packet);
348   return true;
349 }
350 
351 }  // namespace tools
352 }  // namespace net
353