1 /*
2 * Copyright (c) 2020 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 #include "test/network/emulated_turn_server.h"
12
13 #include <string>
14 #include <utility>
15
16 #include "api/packet_socket_factory.h"
17 #include "rtc_base/strings/string_builder.h"
18 #include "rtc_base/task_queue_for_test.h"
19
20 namespace {
21
22 static const char kTestRealm[] = "example.org";
23 static const char kTestSoftware[] = "TestTurnServer";
24
25 // A wrapper class for copying data between an AsyncPacketSocket and a
26 // EmulatedEndpoint. This is used by the cricket::TurnServer when
27 // sending data back into the emulated network.
28 class AsyncPacketSocketWrapper : public rtc::AsyncPacketSocket {
29 public:
AsyncPacketSocketWrapper(webrtc::test::EmulatedTURNServer * turn_server,webrtc::EmulatedEndpoint * endpoint,uint16_t port)30 AsyncPacketSocketWrapper(webrtc::test::EmulatedTURNServer* turn_server,
31 webrtc::EmulatedEndpoint* endpoint,
32 uint16_t port)
33 : turn_server_(turn_server),
34 endpoint_(endpoint),
35 local_address_(
36 rtc::SocketAddress(endpoint_->GetPeerLocalAddress(), port)) {}
~AsyncPacketSocketWrapper()37 ~AsyncPacketSocketWrapper() { turn_server_->Unbind(local_address_); }
38
GetLocalAddress() const39 rtc::SocketAddress GetLocalAddress() const override { return local_address_; }
GetRemoteAddress() const40 rtc::SocketAddress GetRemoteAddress() const override {
41 return rtc::SocketAddress();
42 }
Send(const void * pv,size_t cb,const rtc::PacketOptions & options)43 int Send(const void* pv,
44 size_t cb,
45 const rtc::PacketOptions& options) override {
46 RTC_CHECK(false) << "TCP not implemented";
47 return -1;
48 }
SendTo(const void * pv,size_t cb,const rtc::SocketAddress & addr,const rtc::PacketOptions & options)49 int SendTo(const void* pv,
50 size_t cb,
51 const rtc::SocketAddress& addr,
52 const rtc::PacketOptions& options) override {
53 // Copy from rtc::AsyncPacketSocket to EmulatedEndpoint.
54 rtc::CopyOnWriteBuffer buf(reinterpret_cast<const char*>(pv), cb);
55 endpoint_->SendPacket(local_address_, addr, buf);
56 return cb;
57 }
Close()58 int Close() override { return 0; }
59
GetState() const60 rtc::AsyncPacketSocket::State GetState() const override {
61 return rtc::AsyncPacketSocket::STATE_BOUND;
62 }
GetOption(rtc::Socket::Option opt,int * value)63 int GetOption(rtc::Socket::Option opt, int* value) override { return 0; }
SetOption(rtc::Socket::Option opt,int value)64 int SetOption(rtc::Socket::Option opt, int value) override { return 0; }
GetError() const65 int GetError() const override { return 0; }
SetError(int error)66 void SetError(int error) override {}
67
68 private:
69 webrtc::test::EmulatedTURNServer* const turn_server_;
70 webrtc::EmulatedEndpoint* const endpoint_;
71 const rtc::SocketAddress local_address_;
72 };
73
74 // A wrapper class for cricket::TurnServer to allocate sockets.
75 class PacketSocketFactoryWrapper : public rtc::PacketSocketFactory {
76 public:
PacketSocketFactoryWrapper(webrtc::test::EmulatedTURNServer * turn_server)77 explicit PacketSocketFactoryWrapper(
78 webrtc::test::EmulatedTURNServer* turn_server)
79 : turn_server_(turn_server) {}
~PacketSocketFactoryWrapper()80 ~PacketSocketFactoryWrapper() override {}
81
82 // This method is called from TurnServer when making a TURN ALLOCATION.
83 // It will create a socket on the `peer_` endpoint.
CreateUdpSocket(const rtc::SocketAddress & address,uint16_t min_port,uint16_t max_port)84 rtc::AsyncPacketSocket* CreateUdpSocket(const rtc::SocketAddress& address,
85 uint16_t min_port,
86 uint16_t max_port) override {
87 return turn_server_->CreatePeerSocket();
88 }
89
CreateServerTcpSocket(const rtc::SocketAddress & local_address,uint16_t min_port,uint16_t max_port,int opts)90 rtc::AsyncListenSocket* CreateServerTcpSocket(
91 const rtc::SocketAddress& local_address,
92 uint16_t min_port,
93 uint16_t max_port,
94 int opts) override {
95 return nullptr;
96 }
CreateClientTcpSocket(const rtc::SocketAddress & local_address,const rtc::SocketAddress & remote_address,const rtc::ProxyInfo & proxy_info,const std::string & user_agent,const rtc::PacketSocketTcpOptions & tcp_options)97 rtc::AsyncPacketSocket* CreateClientTcpSocket(
98 const rtc::SocketAddress& local_address,
99 const rtc::SocketAddress& remote_address,
100 const rtc::ProxyInfo& proxy_info,
101 const std::string& user_agent,
102 const rtc::PacketSocketTcpOptions& tcp_options) override {
103 return nullptr;
104 }
CreateAsyncDnsResolver()105 std::unique_ptr<webrtc::AsyncDnsResolverInterface> CreateAsyncDnsResolver()
106 override {
107 return nullptr;
108 }
109
110 private:
111 webrtc::test::EmulatedTURNServer* turn_server_;
112 };
113
114 } // namespace
115
116 namespace webrtc {
117 namespace test {
118
EmulatedTURNServer(std::unique_ptr<rtc::Thread> thread,EmulatedEndpoint * client,EmulatedEndpoint * peer)119 EmulatedTURNServer::EmulatedTURNServer(std::unique_ptr<rtc::Thread> thread,
120 EmulatedEndpoint* client,
121 EmulatedEndpoint* peer)
122 : thread_(std::move(thread)), client_(client), peer_(peer) {
123 ice_config_.username = "keso";
124 ice_config_.password = "keso";
125 SendTask(thread_.get(), [=]() {
126 RTC_DCHECK_RUN_ON(thread_.get());
127 turn_server_ = std::make_unique<cricket::TurnServer>(thread_.get());
128 turn_server_->set_realm(kTestRealm);
129 turn_server_->set_realm(kTestSoftware);
130 turn_server_->set_auth_hook(this);
131
132 auto client_socket = Wrap(client_);
133 turn_server_->AddInternalSocket(client_socket, cricket::PROTO_UDP);
134 turn_server_->SetExternalSocketFactory(new PacketSocketFactoryWrapper(this),
135 rtc::SocketAddress());
136 client_address_ = client_socket->GetLocalAddress();
137 char buf[256];
138 rtc::SimpleStringBuilder str(buf);
139 str.AppendFormat("turn:%s?transport=udp",
140 client_address_.ToString().c_str());
141 ice_config_.url = str.str();
142 });
143 }
144
Stop()145 void EmulatedTURNServer::Stop() {
146 SendTask(thread_.get(), [=]() {
147 RTC_DCHECK_RUN_ON(thread_.get());
148 sockets_.clear();
149 });
150 }
151
~EmulatedTURNServer()152 EmulatedTURNServer::~EmulatedTURNServer() {
153 SendTask(thread_.get(), [=]() {
154 RTC_DCHECK_RUN_ON(thread_.get());
155 turn_server_.reset(nullptr);
156 });
157 }
158
Wrap(EmulatedEndpoint * endpoint)159 rtc::AsyncPacketSocket* EmulatedTURNServer::Wrap(EmulatedEndpoint* endpoint) {
160 RTC_DCHECK_RUN_ON(thread_.get());
161 auto port = endpoint->BindReceiver(0, this).value();
162 auto socket = new AsyncPacketSocketWrapper(this, endpoint, port);
163 sockets_[rtc::SocketAddress(endpoint->GetPeerLocalAddress(), port)] = socket;
164 return socket;
165 }
166
OnPacketReceived(webrtc::EmulatedIpPacket packet)167 void EmulatedTURNServer::OnPacketReceived(webrtc::EmulatedIpPacket packet) {
168 // Copy from EmulatedEndpoint to rtc::AsyncPacketSocket.
169 thread_->PostTask([this, packet(std::move(packet))]() {
170 RTC_DCHECK_RUN_ON(thread_.get());
171 auto it = sockets_.find(packet.to);
172 if (it != sockets_.end()) {
173 it->second->SignalReadPacket(
174 it->second, reinterpret_cast<const char*>(packet.cdata()),
175 packet.size(), packet.from, packet.arrival_time.ms());
176 }
177 });
178 }
179
Unbind(rtc::SocketAddress address)180 void EmulatedTURNServer::Unbind(rtc::SocketAddress address) {
181 RTC_DCHECK_RUN_ON(thread_.get());
182 if (GetClientEndpoint()->GetPeerLocalAddress() == address.ipaddr()) {
183 GetClientEndpoint()->UnbindReceiver(address.port());
184 } else {
185 GetPeerEndpoint()->UnbindReceiver(address.port());
186 }
187 sockets_.erase(address);
188 }
189
190 } // namespace test
191 } // namespace webrtc
192