Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / quic / quic_client.cc
blob86fa6c48b7513925f2d4cc2be590cc53c1f4b637
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/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/flip_server/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"
24 #ifndef SO_RXQ_OVFL
25 #define SO_RXQ_OVFL 40
26 #endif
28 namespace net {
29 namespace tools {
31 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
33 QuicClient::QuicClient(IPEndPoint server_address,
34 const string& server_hostname,
35 const QuicVersion version)
36 : server_address_(server_address),
37 server_hostname_(server_hostname),
38 local_port_(0),
39 fd_(-1),
40 initialized_(false),
41 packets_dropped_(0),
42 overflow_supported_(false),
43 version_(version) {
44 config_.SetDefaults();
47 QuicClient::QuicClient(IPEndPoint server_address,
48 const string& server_hostname,
49 const QuicConfig& config,
50 const QuicVersion version)
51 : server_address_(server_address),
52 server_hostname_(server_hostname),
53 config_(config),
54 local_port_(0),
55 fd_(-1),
56 initialized_(false),
57 packets_dropped_(0),
58 overflow_supported_(false),
59 version_(version) {
62 QuicClient::~QuicClient() {
63 if (connected()) {
64 session()->connection()->SendConnectionClosePacket(
65 QUIC_PEER_GOING_AWAY, "");
69 bool QuicClient::Initialize() {
70 DCHECK(!initialized_);
72 epoll_server_.set_timeout_in_us(50 * 1000);
73 crypto_config_.SetDefaults();
75 int address_family = server_address_.GetSockAddrFamily();
76 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
77 if (fd_ < 0) {
78 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
79 return false;
82 int get_overflow = 1;
83 int rc = setsockopt(fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
84 sizeof(get_overflow));
85 if (rc < 0) {
86 DLOG(WARNING) << "Socket overflow detection not supported";
87 } else {
88 overflow_supported_ = true;
91 int get_local_ip = 1;
92 if (address_family == AF_INET) {
93 rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
94 &get_local_ip, sizeof(get_local_ip));
95 } else {
96 rc = setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
97 &get_local_ip, sizeof(get_local_ip));
100 if (rc < 0) {
101 LOG(ERROR) << "IP detection not supported" << strerror(errno);
102 return false;
105 if (bind_to_address_.size() != 0) {
106 client_address_ = IPEndPoint(bind_to_address_, local_port_);
107 } else if (address_family == AF_INET) {
108 IPAddressNumber any4;
109 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
110 client_address_ = IPEndPoint(any4, local_port_);
111 } else {
112 IPAddressNumber any6;
113 CHECK(net::ParseIPLiteralToNumber("::", &any6));
114 client_address_ = IPEndPoint(any6, local_port_);
117 sockaddr_storage raw_addr;
118 socklen_t raw_addr_len = sizeof(raw_addr);
119 CHECK(client_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
120 &raw_addr_len));
121 rc = bind(fd_,
122 reinterpret_cast<const sockaddr*>(&raw_addr),
123 sizeof(raw_addr));
124 if (rc < 0) {
125 LOG(ERROR) << "Bind failed: " << strerror(errno);
126 return false;
129 SockaddrStorage storage;
130 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
131 !client_address_.FromSockAddr(storage.addr, storage.addr_len)) {
132 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
135 epoll_server_.RegisterFD(fd_, this, kEpollFlags);
136 initialized_ = true;
137 return true;
140 bool QuicClient::Connect() {
141 if (!StartConnect()) {
142 return false;
144 while (EncryptionBeingEstablished()) {
145 WaitForEvents();
147 return session_->connection()->connected();
150 bool QuicClient::StartConnect() {
151 DCHECK(!connected() && initialized_);
153 QuicGuid guid = QuicRandom::GetInstance()->RandUint64();
154 session_.reset(new QuicClientSession(
155 server_hostname_,
156 config_,
157 new QuicConnection(guid, server_address_,
158 CreateQuicConnectionHelper(), false,
159 version_),
160 &crypto_config_));
161 return session_->CryptoConnect();
164 bool QuicClient::EncryptionBeingEstablished() {
165 return !session_->IsEncryptionEstablished() &&
166 session_->connection()->connected();
169 void QuicClient::Disconnect() {
170 DCHECK(connected());
172 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
173 epoll_server_.UnregisterFD(fd_);
174 close(fd_);
175 fd_ = -1;
176 initialized_ = false;
179 void QuicClient::SendRequestsAndWaitForResponse(
180 const CommandLine::StringVector& args) {
181 for (uint32_t i = 0; i < args.size(); i++) {
182 BalsaHeaders headers;
183 headers.SetRequestFirstlineFromStringPieces("GET", args[i], "HTTP/1.1");
184 CreateReliableClientStream()->SendRequest(headers, "", true);
187 while (WaitForEvents()) { }
190 QuicReliableClientStream* QuicClient::CreateReliableClientStream() {
191 if (!connected()) {
192 return NULL;
195 return session_->CreateOutgoingReliableStream();
198 void QuicClient::WaitForStreamToClose(QuicStreamId id) {
199 DCHECK(connected());
201 while (!session_->IsClosedStream(id)) {
202 epoll_server_.WaitForEventsAndExecuteCallbacks();
206 void QuicClient::WaitForCryptoHandshakeConfirmed() {
207 DCHECK(connected());
209 while (!session_->IsCryptoHandshakeConfirmed()) {
210 epoll_server_.WaitForEventsAndExecuteCallbacks();
214 bool QuicClient::WaitForEvents() {
215 DCHECK(connected());
217 epoll_server_.WaitForEventsAndExecuteCallbacks();
218 return session_->num_active_requests() != 0;
221 void QuicClient::OnEvent(int fd, EpollEvent* event) {
222 DCHECK_EQ(fd, fd_);
224 if (event->in_events & EPOLLIN) {
225 while (connected() && ReadAndProcessPacket()) {
228 if (connected() && (event->in_events & EPOLLOUT)) {
229 session_->connection()->OnCanWrite();
231 if (event->in_events & EPOLLERR) {
232 DLOG(INFO) << "Epollerr";
236 QuicPacketCreator::Options* QuicClient::options() {
237 if (session() == NULL) {
238 return NULL;
240 return session_->options();
243 bool QuicClient::connected() const {
244 return session_.get() && session_->connection() &&
245 session_->connection()->connected();
248 QuicEpollConnectionHelper* QuicClient::CreateQuicConnectionHelper() {
249 return new QuicEpollConnectionHelper(fd_, &epoll_server_);
252 bool QuicClient::ReadAndProcessPacket() {
253 // Allocate some extra space so we can send an error if the server goes over
254 // the limit.
255 char buf[2 * kMaxPacketSize];
257 IPEndPoint server_address;
258 IPAddressNumber client_ip;
260 int bytes_read = QuicSocketUtils::ReadPacket(
261 fd_, buf, arraysize(buf), overflow_supported_ ? &packets_dropped_ : NULL,
262 &client_ip, &server_address);
264 if (bytes_read < 0) {
265 return false;
268 QuicEncryptedPacket packet(buf, bytes_read, false);
269 QuicGuid our_guid = session_->connection()->guid();
270 QuicGuid packet_guid;
272 if (!QuicFramer::ReadGuidFromPacket(packet, &packet_guid)) {
273 DLOG(INFO) << "Could not read GUID from packet";
274 return true;
276 if (packet_guid != our_guid) {
277 DLOG(INFO) << "Ignoring packet from unexpected GUID: "
278 << packet_guid << " instead of " << our_guid;
279 return true;
282 IPEndPoint client_address(client_ip, client_address_.port());
283 session_->connection()->ProcessUdpPacket(
284 client_address, server_address, packet);
285 return true;
288 } // namespace tools
289 } // namespace net