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