1 /* 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef P2P_BASE_TEST_TURN_SERVER_H_ 12 #define P2P_BASE_TEST_TURN_SERVER_H_ 13 14 #include <string> 15 #include <vector> 16 17 #include "api/transport/stun.h" 18 #include "p2p/base/basic_packet_socket_factory.h" 19 #include "p2p/base/turn_server.h" 20 #include "rtc_base/async_udp_socket.h" 21 #include "rtc_base/ssl_adapter.h" 22 #include "rtc_base/ssl_identity.h" 23 #include "rtc_base/thread.h" 24 #include "rtc_base/thread_checker.h" 25 26 namespace cricket { 27 28 static const char kTestRealm[] = "example.org"; 29 static const char kTestSoftware[] = "TestTurnServer"; 30 31 class TestTurnRedirector : public TurnRedirectInterface { 32 public: TestTurnRedirector(const std::vector<rtc::SocketAddress> & addresses)33 explicit TestTurnRedirector(const std::vector<rtc::SocketAddress>& addresses) 34 : alternate_server_addresses_(addresses), 35 iter_(alternate_server_addresses_.begin()) {} 36 ShouldRedirect(const rtc::SocketAddress &,rtc::SocketAddress * out)37 virtual bool ShouldRedirect(const rtc::SocketAddress&, 38 rtc::SocketAddress* out) { 39 if (!out || iter_ == alternate_server_addresses_.end()) { 40 return false; 41 } 42 *out = *iter_++; 43 return true; 44 } 45 46 private: 47 const std::vector<rtc::SocketAddress>& alternate_server_addresses_; 48 std::vector<rtc::SocketAddress>::const_iterator iter_; 49 }; 50 51 class TestTurnServer : public TurnAuthInterface { 52 public: 53 TestTurnServer(rtc::Thread* thread, 54 const rtc::SocketAddress& int_addr, 55 const rtc::SocketAddress& udp_ext_addr, 56 ProtocolType int_protocol = PROTO_UDP, 57 bool ignore_bad_cert = true, 58 const std::string& common_name = "test turn server") server_(thread)59 : server_(thread), thread_(thread) { 60 AddInternalSocket(int_addr, int_protocol, ignore_bad_cert, common_name); 61 server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(thread), 62 udp_ext_addr); 63 server_.set_realm(kTestRealm); 64 server_.set_software(kTestSoftware); 65 server_.set_auth_hook(this); 66 } 67 ~TestTurnServer()68 ~TestTurnServer() { RTC_DCHECK(thread_checker_.IsCurrent()); } 69 set_enable_otu_nonce(bool enable)70 void set_enable_otu_nonce(bool enable) { 71 RTC_DCHECK(thread_checker_.IsCurrent()); 72 server_.set_enable_otu_nonce(enable); 73 } 74 server()75 TurnServer* server() { 76 RTC_DCHECK(thread_checker_.IsCurrent()); 77 return &server_; 78 } 79 set_redirect_hook(TurnRedirectInterface * redirect_hook)80 void set_redirect_hook(TurnRedirectInterface* redirect_hook) { 81 RTC_DCHECK(thread_checker_.IsCurrent()); 82 server_.set_redirect_hook(redirect_hook); 83 } 84 set_enable_permission_checks(bool enable)85 void set_enable_permission_checks(bool enable) { 86 RTC_DCHECK(thread_checker_.IsCurrent()); 87 server_.set_enable_permission_checks(enable); 88 } 89 90 void AddInternalSocket(const rtc::SocketAddress& int_addr, 91 ProtocolType proto, 92 bool ignore_bad_cert = true, 93 const std::string& common_name = "test turn server") { 94 RTC_DCHECK(thread_checker_.IsCurrent()); 95 if (proto == cricket::PROTO_UDP) { 96 server_.AddInternalSocket( 97 rtc::AsyncUDPSocket::Create(thread_->socketserver(), int_addr), 98 proto); 99 } else if (proto == cricket::PROTO_TCP || proto == cricket::PROTO_TLS) { 100 // For TCP we need to create a server socket which can listen for incoming 101 // new connections. 102 rtc::AsyncSocket* socket = 103 thread_->socketserver()->CreateAsyncSocket(AF_INET, SOCK_STREAM); 104 if (proto == cricket::PROTO_TLS) { 105 // For TLS, wrap the TCP socket with an SSL adapter. The adapter must 106 // be configured with a self-signed certificate for testing. 107 // Additionally, the client will not present a valid certificate, so we 108 // must not fail when checking the peer's identity. 109 rtc::SSLAdapter* adapter = rtc::SSLAdapter::Create(socket); 110 adapter->SetRole(rtc::SSL_SERVER); 111 adapter->SetIdentity( 112 rtc::SSLIdentity::Create(common_name, rtc::KeyParams())); 113 adapter->SetIgnoreBadCert(ignore_bad_cert); 114 socket = adapter; 115 } 116 socket->Bind(int_addr); 117 socket->Listen(5); 118 server_.AddInternalServerSocket(socket, proto); 119 } else { 120 RTC_NOTREACHED() << "Unknown protocol type: " << proto; 121 } 122 } 123 124 // Finds the first allocation in the server allocation map with a source 125 // ip and port matching the socket address provided. FindAllocation(const rtc::SocketAddress & src)126 TurnServerAllocation* FindAllocation(const rtc::SocketAddress& src) { 127 RTC_DCHECK(thread_checker_.IsCurrent()); 128 const TurnServer::AllocationMap& map = server_.allocations(); 129 for (TurnServer::AllocationMap::const_iterator it = map.begin(); 130 it != map.end(); ++it) { 131 if (src == it->first.src()) { 132 return it->second.get(); 133 } 134 } 135 return NULL; 136 } 137 138 private: 139 // For this test server, succeed if the password is the same as the username. 140 // Obviously, do not use this in a production environment. GetKey(const std::string & username,const std::string & realm,std::string * key)141 virtual bool GetKey(const std::string& username, 142 const std::string& realm, 143 std::string* key) { 144 RTC_DCHECK(thread_checker_.IsCurrent()); 145 return ComputeStunCredentialHash(username, realm, username, key); 146 } 147 148 TurnServer server_; 149 rtc::Thread* thread_; 150 rtc::ThreadChecker thread_checker_; 151 }; 152 153 } // namespace cricket 154 155 #endif // P2P_BASE_TEST_TURN_SERVER_H_ 156