1 // Copyright 2013 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/third_party/quiche/src/quic/test_tools/server_thread.h"
6 
7 #include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
8 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
9 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
10 #include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h"
11 
12 namespace quic {
13 namespace test {
14 
ServerThread(QuicServer * server,const QuicSocketAddress & address)15 ServerThread::ServerThread(QuicServer* server, const QuicSocketAddress& address)
16     : QuicThread("server_thread"),
17       server_(server),
18       clock_(server->epoll_server()),
19       address_(address),
20       port_(0),
21       initialized_(false) {}
22 
23 ServerThread::~ServerThread() = default;
24 
Initialize()25 void ServerThread::Initialize() {
26   if (initialized_) {
27     return;
28   }
29 
30   server_->CreateUDPSocketAndListen(address_);
31 
32   QuicWriterMutexLock lock(&port_lock_);
33   port_ = server_->port();
34 
35   initialized_ = true;
36 }
37 
Run()38 void ServerThread::Run() {
39   if (!initialized_) {
40     Initialize();
41   }
42 
43   while (!quit_.HasBeenNotified()) {
44     if (pause_.HasBeenNotified() && !resume_.HasBeenNotified()) {
45       paused_.Notify();
46       resume_.WaitForNotification();
47     }
48     server_->WaitForEvents();
49     ExecuteScheduledActions();
50     MaybeNotifyOfHandshakeConfirmation();
51   }
52 
53   server_->Shutdown();
54 }
55 
GetPort()56 int ServerThread::GetPort() {
57   QuicReaderMutexLock lock(&port_lock_);
58   int rc = port_;
59   return rc;
60 }
61 
Schedule(std::function<void ()> action)62 void ServerThread::Schedule(std::function<void()> action) {
63   DCHECK(!quit_.HasBeenNotified());
64   QuicWriterMutexLock lock(&scheduled_actions_lock_);
65   scheduled_actions_.push_back(std::move(action));
66 }
67 
WaitForCryptoHandshakeConfirmed()68 void ServerThread::WaitForCryptoHandshakeConfirmed() {
69   confirmed_.WaitForNotification();
70 }
71 
WaitUntil(std::function<bool ()> termination_predicate,QuicTime::Delta timeout)72 bool ServerThread::WaitUntil(std::function<bool()> termination_predicate,
73                              QuicTime::Delta timeout) {
74   const QuicTime deadline = clock_.Now() + timeout;
75   while (clock_.Now() < deadline) {
76     QuicNotification done_checking;
77     bool should_terminate = false;
78     Schedule([&] {
79       should_terminate = termination_predicate();
80       done_checking.Notify();
81     });
82     done_checking.WaitForNotification();
83     if (should_terminate) {
84       return true;
85     }
86   }
87   return false;
88 }
89 
Pause()90 void ServerThread::Pause() {
91   DCHECK(!pause_.HasBeenNotified());
92   pause_.Notify();
93   paused_.WaitForNotification();
94 }
95 
Resume()96 void ServerThread::Resume() {
97   DCHECK(!resume_.HasBeenNotified());
98   DCHECK(pause_.HasBeenNotified());
99   resume_.Notify();
100 }
101 
Quit()102 void ServerThread::Quit() {
103   if (pause_.HasBeenNotified() && !resume_.HasBeenNotified()) {
104     resume_.Notify();
105   }
106   if (!quit_.HasBeenNotified()) {
107     quit_.Notify();
108   }
109 }
110 
MaybeNotifyOfHandshakeConfirmation()111 void ServerThread::MaybeNotifyOfHandshakeConfirmation() {
112   if (confirmed_.HasBeenNotified()) {
113     // Only notify once.
114     return;
115   }
116   QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server());
117   if (dispatcher->session_map().empty()) {
118     // Wait for a session to be created.
119     return;
120   }
121   QuicSession* session = dispatcher->session_map().begin()->second.get();
122   if (session->OneRttKeysAvailable()) {
123     confirmed_.Notify();
124   }
125 }
126 
ExecuteScheduledActions()127 void ServerThread::ExecuteScheduledActions() {
128   QuicCircularDeque<std::function<void()>> actions;
129   {
130     QuicWriterMutexLock lock(&scheduled_actions_lock_);
131     actions.swap(scheduled_actions_);
132   }
133   while (!actions.empty()) {
134     actions.front()();
135     actions.pop_front();
136   }
137 }
138 
139 }  // namespace test
140 }  // namespace quic
141