1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/tools/quic/quic_dispatcher.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <errno.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/quic/quic_blocked_writer_interface.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/quic/quic_utils.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/tools/quic/quic_epoll_connection_helper.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/tools/quic/quic_socket_utils.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace net {
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace tools {
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using std::make_pair;
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class DeleteSessionsAlarm : public EpollAlarm {
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : dispatcher_(dispatcher) {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual int64 OnAlarm() OVERRIDE {
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EpollAlarm::OnAlarm();
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dispatcher_->DeleteSessions();
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0;
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  QuicDispatcher* dispatcher_;
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)QuicDispatcher::QuicDispatcher(const QuicConfig& config,
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               const QuicCryptoServerConfig& crypto_config,
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               int fd,
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               EpollServer* epoll_server)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : config_(config),
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      crypto_config_(crypto_config),
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      time_wait_list_manager_(
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          new QuicTimeWaitListManager(this, epoll_server)),
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      delete_sessions_alarm_(new DeleteSessionsAlarm(this)),
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      epoll_server_(epoll_server),
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      fd_(fd),
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      write_blocked_(false) {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)QuicDispatcher::~QuicDispatcher() {
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  STLDeleteValues(&session_map_);
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  STLDeleteElements(&closed_session_list_);
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int QuicDispatcher::WritePacket(const char* buffer, size_t buf_len,
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                const IPAddressNumber& self_address,
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                const IPEndPoint& peer_address,
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                QuicBlockedWriterInterface* writer,
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                int* error) {
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (write_blocked_) {
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    write_blocked_list_.AddBlockedObject(writer);
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *error = EAGAIN;
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return -1;
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int rc = QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        self_address, peer_address,
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        error);
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (rc == -1 && (*error == EWOULDBLOCK || *error == EAGAIN)) {
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    write_blocked_list_.AddBlockedObject(writer);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    write_blocked_ = true;
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return rc;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                   const IPEndPoint& client_address,
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                   QuicGuid guid,
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                   const QuicEncryptedPacket& packet) {
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  QuicSession* session;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SessionMap::iterator it = session_map_.find(guid);
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (it == session_map_.end()) {
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (time_wait_list_manager_->IsGuidInTimeWait(guid)) {
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      time_wait_list_manager_->ProcessPacket(server_address,
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             client_address,
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             guid,
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             packet);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session = CreateQuicSession(guid, client_address, fd_, epoll_server_);
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (session == NULL) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DLOG(INFO) << "Failed to create session for " << guid;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Add this guid fo the time-wait state, to safely nack future packets.
97558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // We don't know the version here, so assume latest.
98558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      time_wait_list_manager_->AddGuidToTimeWait(guid, QuicVersionMax());
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      time_wait_list_manager_->ProcessPacket(server_address,
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             client_address,
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             guid,
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             packet);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DLOG(INFO) << "Created new session for " << guid;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session_map_.insert(make_pair(guid, session));
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session = it->second;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session->connection()->ProcessUdpPacket(
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      server_address, client_address, packet);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  QuicSession* session = it->second;
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_blocked_list_.RemoveBlockedObject(session->connection());
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  time_wait_list_manager_->AddGuidToTimeWait(it->first,
119558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                             session->connection()->version());
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  session_map_.erase(it);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicDispatcher::DeleteSessions() {
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  STLDeleteElements(&closed_session_list_);
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool QuicDispatcher::OnCanWrite() {
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We got an EPOLLOUT: the socket should not be blocked.
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  write_blocked_ = false;
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Give each writer one attempt to write.
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int num_writers = write_blocked_list_.NumObjects();
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < num_writers; ++i) {
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (write_blocked_list_.IsEmpty()) {
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    QuicBlockedWriterInterface* writer =
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        write_blocked_list_.GetNextBlockedObject();
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool can_write_more = writer->OnCanWrite();
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (write_blocked_) {
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // We were unable to write.  Wait for the next EPOLLOUT.
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // In this case, the session would have been added to the blocked list
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // up in WritePacket.
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The socket is not blocked but the writer has ceded work.  Add it to the
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // end of the list.
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (can_write_more) {
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      write_blocked_list_.AddBlockedObject(writer);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We're not write blocked.  Return true if there's more work to do.
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return !write_blocked_list_.IsEmpty();
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicDispatcher::Shutdown() {
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (!session_map_.empty()) {
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    QuicSession* session = session_map_.begin()->second;
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Validate that the session removes itself from the session map on close.
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(session_map_.empty() || session_map_.begin()->second != session);
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteSessions();
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicDispatcher::OnConnectionClose(QuicGuid guid, QuicErrorCode error) {
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SessionMap::iterator it = session_map_.find(guid);
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (it == session_map_.end()) {
1702385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    LOG(DFATAL) << "GUID " << guid << " does not exist in the session map.  "
1712385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch                << "Error: " << QuicUtils::ErrorToString(error);
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DLOG_IF(INFO, error != QUIC_NO_ERROR) << "Closing connection due to error: "
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        << QuicUtils::ErrorToString(error);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (closed_session_list_.empty()) {
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    epoll_server_->RegisterAlarmApproximateDelta(
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        0, delete_sessions_alarm_.get());
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  closed_session_list_.push_back(it->second);
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CleanUpSession(it);
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)QuicSession* QuicDispatcher::CreateQuicSession(
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    QuicGuid guid,
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const IPEndPoint& client_address,
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int fd,
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EpollServer* epoll_server) {
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  QuicConnectionHelperInterface* helper =
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new QuicEpollConnectionHelper(this, epoll_server);
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  QuicServerSession* session = new QuicServerSession(
194558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch       config_, new QuicConnection(guid, client_address, helper, true,
195558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                   QuicVersionMax()), this);
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  session->InitializeSession(crypto_config_);
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return session;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace tools
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace net
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
204