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