Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / quic / quic_dispatcher.cc
blob68691f7dc58b2613a820cc4ffa5147b3ae047915
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_dispatcher.h"
7 #include <errno.h>
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "net/quic/quic_blocked_writer_interface.h"
12 #include "net/quic/quic_utils.h"
13 #include "net/tools/quic/quic_epoll_connection_helper.h"
14 #include "net/tools/quic/quic_socket_utils.h"
16 namespace net {
17 namespace tools {
19 using std::make_pair;
21 class DeleteSessionsAlarm : public EpollAlarm {
22 public:
23 explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
24 : dispatcher_(dispatcher) {
27 virtual int64 OnAlarm() OVERRIDE {
28 EpollAlarm::OnAlarm();
29 dispatcher_->DeleteSessions();
30 return 0;
33 private:
34 QuicDispatcher* dispatcher_;
37 QuicDispatcher::QuicDispatcher(const QuicConfig& config,
38 const QuicCryptoServerConfig& crypto_config,
39 int fd,
40 EpollServer* epoll_server)
41 : config_(config),
42 crypto_config_(crypto_config),
43 time_wait_list_manager_(
44 new QuicTimeWaitListManager(this, epoll_server)),
45 delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
46 epoll_server_(epoll_server),
47 fd_(fd),
48 write_blocked_(false) {
51 QuicDispatcher::~QuicDispatcher() {
52 STLDeleteValues(&session_map_);
53 STLDeleteElements(&closed_session_list_);
56 int QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
57 const IPAddressNumber& self_address,
58 const IPEndPoint& peer_address,
59 QuicBlockedWriterInterface* writer,
60 int* error) {
61 if (write_blocked_) {
62 write_blocked_list_.AddBlockedObject(writer);
63 *error = EAGAIN;
64 return -1;
67 int rc = QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
68 self_address, peer_address,
69 error);
70 if (rc == -1 && (*error == EWOULDBLOCK || *error == EAGAIN)) {
71 write_blocked_list_.AddBlockedObject(writer);
72 write_blocked_ = true;
74 return rc;
77 void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
78 const IPEndPoint& client_address,
79 QuicGuid guid,
80 const QuicEncryptedPacket& packet) {
81 QuicSession* session;
83 SessionMap::iterator it = session_map_.find(guid);
84 if (it == session_map_.end()) {
85 if (time_wait_list_manager_->IsGuidInTimeWait(guid)) {
86 time_wait_list_manager_->ProcessPacket(server_address,
87 client_address,
88 guid,
89 packet);
90 return;
92 session = CreateQuicSession(guid, client_address, fd_, epoll_server_);
94 if (session == NULL) {
95 DLOG(INFO) << "Failed to create session for " << guid;
96 // Add this guid fo the time-wait state, to safely nack future packets.
97 // We don't know the version here, so assume latest.
98 time_wait_list_manager_->AddGuidToTimeWait(guid, QuicVersionMax());
99 time_wait_list_manager_->ProcessPacket(server_address,
100 client_address,
101 guid,
102 packet);
103 return;
105 DLOG(INFO) << "Created new session for " << guid;
106 session_map_.insert(make_pair(guid, session));
107 } else {
108 session = it->second;
111 session->connection()->ProcessUdpPacket(
112 server_address, client_address, packet);
115 void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
116 QuicSession* session = it->second;
117 write_blocked_list_.RemoveBlockedObject(session->connection());
118 time_wait_list_manager_->AddGuidToTimeWait(it->first,
119 session->connection()->version());
120 session_map_.erase(it);
123 void QuicDispatcher::DeleteSessions() {
124 STLDeleteElements(&closed_session_list_);
127 bool QuicDispatcher::OnCanWrite() {
128 // We got an EPOLLOUT: the socket should not be blocked.
129 write_blocked_ = false;
131 // Give each writer one attempt to write.
132 int num_writers = write_blocked_list_.NumObjects();
133 for (int i = 0; i < num_writers; ++i) {
134 if (write_blocked_list_.IsEmpty()) {
135 break;
137 QuicBlockedWriterInterface* writer =
138 write_blocked_list_.GetNextBlockedObject();
139 bool can_write_more = writer->OnCanWrite();
140 if (write_blocked_) {
141 // We were unable to write. Wait for the next EPOLLOUT.
142 // In this case, the session would have been added to the blocked list
143 // up in WritePacket.
144 return false;
146 // The socket is not blocked but the writer has ceded work. Add it to the
147 // end of the list.
148 if (can_write_more) {
149 write_blocked_list_.AddBlockedObject(writer);
153 // We're not write blocked. Return true if there's more work to do.
154 return !write_blocked_list_.IsEmpty();
157 void QuicDispatcher::Shutdown() {
158 while (!session_map_.empty()) {
159 QuicSession* session = session_map_.begin()->second;
160 session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
161 // Validate that the session removes itself from the session map on close.
162 DCHECK(session_map_.empty() || session_map_.begin()->second != session);
164 DeleteSessions();
167 void QuicDispatcher::OnConnectionClose(QuicGuid guid, QuicErrorCode error) {
168 SessionMap::iterator it = session_map_.find(guid);
169 if (it == session_map_.end()) {
170 LOG(DFATAL) << "GUID " << guid << " does not exist in the session map. "
171 << "Error: " << QuicUtils::ErrorToString(error);
172 return;
175 DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection due to error: "
176 << QuicUtils::ErrorToString(error);
178 if (closed_session_list_.empty()) {
179 epoll_server_->RegisterAlarmApproximateDelta(
180 0, delete_sessions_alarm_.get());
182 closed_session_list_.push_back(it->second);
183 CleanUpSession(it);
186 QuicSession* QuicDispatcher::CreateQuicSession(
187 QuicGuid guid,
188 const IPEndPoint& client_address,
189 int fd,
190 EpollServer* epoll_server) {
191 QuicConnectionHelperInterface* helper =
192 new QuicEpollConnectionHelper(this, epoll_server);
193 QuicServerSession* session = new QuicServerSession(
194 config_, new QuicConnection(guid, client_address, helper, true,
195 QuicVersionMax()), this);
196 session->InitializeSession(crypto_config_);
197 return session;
200 } // namespace tools
201 } // namespace net