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