blob: d162950a3bb1e87f6493589d0f10541ee1636910 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2009, Google, Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef TALK_P2P_BASE_FAKESESSION_H_
29#define TALK_P2P_BASE_FAKESESSION_H_
30
31#include <map>
32#include <string>
33#include <vector>
34
35#include "talk/base/buffer.h"
36#include "talk/base/sigslot.h"
37#include "talk/base/sslfingerprint.h"
38#include "talk/base/messagequeue.h"
39#include "talk/p2p/base/session.h"
40#include "talk/p2p/base/transport.h"
41#include "talk/p2p/base/transportchannel.h"
42#include "talk/p2p/base/transportchannelimpl.h"
43
44namespace cricket {
45
46class FakeTransport;
47
48struct PacketMessageData : public talk_base::MessageData {
49 PacketMessageData(const char* data, size_t len) : packet(data, len) {
50 }
51 talk_base::Buffer packet;
52};
53
54// Fake transport channel class, which can be passed to anything that needs a
55// transport channel. Can be informed of another FakeTransportChannel via
56// SetDestination.
57class FakeTransportChannel : public TransportChannelImpl,
58 public talk_base::MessageHandler {
59 public:
60 explicit FakeTransportChannel(Transport* transport,
61 const std::string& content_name,
62 int component)
63 : TransportChannelImpl(content_name, component),
64 transport_(transport),
65 dest_(NULL),
66 state_(STATE_INIT),
67 async_(false),
68 identity_(NULL),
69 do_dtls_(false),
mallinath@webrtc.orga5506692013-08-12 21:18:15 +000070 role_(ICEROLE_UNKNOWN),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071 tiebreaker_(0),
72 ice_proto_(ICEPROTO_HYBRID),
73 remote_ice_mode_(ICEMODE_FULL),
mallinath@webrtc.orgaf84d782013-08-26 17:14:13 +000074 dtls_fingerprint_("", NULL, 0),
75 ssl_role_(talk_base::SSL_CLIENT) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076 }
77 ~FakeTransportChannel() {
78 Reset();
79 }
80
mallinath@webrtc.orga5506692013-08-12 21:18:15 +000081 uint64 IceTiebreaker() const { return tiebreaker_; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082 TransportProtocol protocol() const { return ice_proto_; }
83 IceMode remote_ice_mode() const { return remote_ice_mode_; }
84 const std::string& ice_ufrag() const { return ice_ufrag_; }
85 const std::string& ice_pwd() const { return ice_pwd_; }
86 const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; }
87 const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
88 const talk_base::SSLFingerprint& dtls_fingerprint() const {
89 return dtls_fingerprint_;
90 }
91
92 void SetAsync(bool async) {
93 async_ = async;
94 }
95
96 virtual Transport* GetTransport() {
97 return transport_;
98 }
99
mallinath@webrtc.orga5506692013-08-12 21:18:15 +0000100 virtual void SetIceRole(IceRole role) { role_ = role; }
101 virtual IceRole GetIceRole() const { return role_; }
102 virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103 virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
104 virtual void SetIceCredentials(const std::string& ice_ufrag,
105 const std::string& ice_pwd) {
106 ice_ufrag_ = ice_ufrag;
107 ice_pwd_ = ice_pwd;
108 }
109 virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
110 const std::string& ice_pwd) {
111 remote_ice_ufrag_ = ice_ufrag;
112 remote_ice_pwd_ = ice_pwd;
113 }
114
115 virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; }
116 virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest,
117 size_t digest_len) {
118 dtls_fingerprint_ = talk_base::SSLFingerprint(alg, digest, digest_len);
119 return true;
120 }
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000121 virtual bool SetSslRole(talk_base::SSLRole role) {
122 ssl_role_ = role;
123 return true;
124 }
125 virtual bool GetSslRole(talk_base::SSLRole* role) const {
126 *role = ssl_role_;
127 return true;
128 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129
130 virtual void Connect() {
131 if (state_ == STATE_INIT) {
132 state_ = STATE_CONNECTING;
133 }
134 }
135 virtual void Reset() {
136 if (state_ != STATE_INIT) {
137 state_ = STATE_INIT;
138 if (dest_) {
139 dest_->state_ = STATE_INIT;
140 dest_->dest_ = NULL;
141 dest_ = NULL;
142 }
143 }
144 }
145
146 void SetWritable(bool writable) {
147 set_writable(writable);
148 }
149
150 void SetDestination(FakeTransportChannel* dest) {
151 if (state_ == STATE_CONNECTING && dest) {
152 // This simulates the delivery of candidates.
153 dest_ = dest;
154 dest_->dest_ = this;
155 if (identity_ && dest_->identity_) {
156 do_dtls_ = true;
157 dest_->do_dtls_ = true;
158 NegotiateSrtpCiphers();
159 }
160 state_ = STATE_CONNECTED;
161 dest_->state_ = STATE_CONNECTED;
162 set_writable(true);
163 dest_->set_writable(true);
164 } else if (state_ == STATE_CONNECTED && !dest) {
165 // Simulates loss of connectivity, by asymmetrically forgetting dest_.
166 dest_ = NULL;
167 state_ = STATE_CONNECTING;
168 set_writable(false);
169 }
170 }
171
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000172 virtual int SendPacket(const char* data, size_t len,
173 talk_base::DiffServCodePoint dscp, int flags) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174 if (state_ != STATE_CONNECTED) {
175 return -1;
176 }
177
178 if (flags != PF_SRTP_BYPASS && flags != 0) {
179 return -1;
180 }
181
182 PacketMessageData* packet = new PacketMessageData(data, len);
183 if (async_) {
184 talk_base::Thread::Current()->Post(this, 0, packet);
185 } else {
186 talk_base::Thread::Current()->Send(this, 0, packet);
187 }
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000188 return static_cast<int>(len);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000189 }
190 virtual int SetOption(talk_base::Socket::Option opt, int value) {
191 return true;
192 }
193 virtual int GetError() {
194 return 0;
195 }
196
197 virtual void OnSignalingReady() {
198 }
199 virtual void OnCandidate(const Candidate& candidate) {
200 }
201
202 virtual void OnMessage(talk_base::Message* msg) {
203 PacketMessageData* data = static_cast<PacketMessageData*>(
204 msg->pdata);
205 dest_->SignalReadPacket(dest_, data->packet.data(),
206 data->packet.length(), 0);
207 delete data;
208 }
209
210 bool SetLocalIdentity(talk_base::SSLIdentity* identity) {
211 identity_ = identity;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212 return true;
213 }
214
215 bool IsDtlsActive() const {
216 return do_dtls_;
217 }
218
219 bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
220 srtp_ciphers_ = ciphers;
221 return true;
222 }
223
224 virtual bool GetSrtpCipher(std::string* cipher) {
225 if (!chosen_srtp_cipher_.empty()) {
226 *cipher = chosen_srtp_cipher_;
227 return true;
228 }
229 return false;
230 }
231
232 virtual bool ExportKeyingMaterial(const std::string& label,
233 const uint8* context,
234 size_t context_len,
235 bool use_context,
236 uint8* result,
237 size_t result_len) {
238 if (!chosen_srtp_cipher_.empty()) {
239 memset(result, 0xff, result_len);
240 return true;
241 }
242
243 return false;
244 }
245
246 virtual void NegotiateSrtpCiphers() {
247 for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
248 it1 != srtp_ciphers_.end(); ++it1) {
249 for (std::vector<std::string>::const_iterator it2 =
250 dest_->srtp_ciphers_.begin();
251 it2 != dest_->srtp_ciphers_.end(); ++it2) {
252 if (*it1 == *it2) {
253 chosen_srtp_cipher_ = *it1;
254 dest_->chosen_srtp_cipher_ = *it2;
255 return;
256 }
257 }
258 }
259 }
260
261 virtual bool GetStats(ConnectionInfos* infos) OVERRIDE {
262 ConnectionInfo info;
263 infos->clear();
264 infos->push_back(info);
265 return true;
266 }
267
268 private:
269 enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
270 Transport* transport_;
271 FakeTransportChannel* dest_;
272 State state_;
273 bool async_;
274 talk_base::SSLIdentity* identity_;
275 bool do_dtls_;
276 std::vector<std::string> srtp_ciphers_;
277 std::string chosen_srtp_cipher_;
mallinath@webrtc.orga5506692013-08-12 21:18:15 +0000278 IceRole role_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 uint64 tiebreaker_;
280 IceProtocolType ice_proto_;
281 std::string ice_ufrag_;
282 std::string ice_pwd_;
283 std::string remote_ice_ufrag_;
284 std::string remote_ice_pwd_;
285 IceMode remote_ice_mode_;
286 talk_base::SSLFingerprint dtls_fingerprint_;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000287 talk_base::SSLRole ssl_role_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288};
289
290// Fake transport class, which can be passed to anything that needs a Transport.
291// Can be informed of another FakeTransport via SetDestination (low-tech way
292// of doing candidates)
293class FakeTransport : public Transport {
294 public:
295 typedef std::map<int, FakeTransportChannel*> ChannelMap;
296 FakeTransport(talk_base::Thread* signaling_thread,
297 talk_base::Thread* worker_thread,
298 const std::string& content_name,
299 PortAllocator* alllocator = NULL)
300 : Transport(signaling_thread, worker_thread,
301 content_name, "test_type", NULL),
302 dest_(NULL),
303 async_(false),
304 identity_(NULL) {
305 }
306 ~FakeTransport() {
307 DestroyAllChannels();
308 }
309
310 const ChannelMap& channels() const { return channels_; }
311
312 void SetAsync(bool async) { async_ = async; }
313 void SetDestination(FakeTransport* dest) {
314 dest_ = dest;
315 for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
316 ++it) {
317 it->second->SetLocalIdentity(identity_);
318 SetChannelDestination(it->first, it->second);
319 }
320 }
321
322 void SetWritable(bool writable) {
323 for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
324 ++it) {
325 it->second->SetWritable(writable);
326 }
327 }
328
329 void set_identity(talk_base::SSLIdentity* identity) {
330 identity_ = identity;
331 }
332
333 using Transport::local_description;
334 using Transport::remote_description;
335
336 protected:
337 virtual TransportChannelImpl* CreateTransportChannel(int component) {
338 if (channels_.find(component) != channels_.end()) {
339 return NULL;
340 }
341 FakeTransportChannel* channel =
342 new FakeTransportChannel(this, content_name(), component);
343 channel->SetAsync(async_);
344 SetChannelDestination(component, channel);
345 channels_[component] = channel;
346 return channel;
347 }
348 virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
349 channels_.erase(channel->component());
350 delete channel;
351 }
352
353 private:
354 FakeTransportChannel* GetFakeChannel(int component) {
355 ChannelMap::iterator it = channels_.find(component);
356 return (it != channels_.end()) ? it->second : NULL;
357 }
358 void SetChannelDestination(int component,
359 FakeTransportChannel* channel) {
360 FakeTransportChannel* dest_channel = NULL;
361 if (dest_) {
362 dest_channel = dest_->GetFakeChannel(component);
363 if (dest_channel) {
364 dest_channel->SetLocalIdentity(dest_->identity_);
365 }
366 }
367 channel->SetDestination(dest_channel);
368 }
369
370 // Note, this is distinct from the Channel map owned by Transport.
371 // This map just tracks the FakeTransportChannels created by this class.
372 ChannelMap channels_;
373 FakeTransport* dest_;
374 bool async_;
375 talk_base::SSLIdentity* identity_;
376};
377
378// Fake session class, which can be passed into a BaseChannel object for
379// test purposes. Can be connected to other FakeSessions via Connect().
380class FakeSession : public BaseSession {
381 public:
382 explicit FakeSession()
383 : BaseSession(talk_base::Thread::Current(),
384 talk_base::Thread::Current(),
385 NULL, "", "", true),
386 fail_create_channel_(false) {
387 }
388 explicit FakeSession(bool initiator)
389 : BaseSession(talk_base::Thread::Current(),
390 talk_base::Thread::Current(),
391 NULL, "", "", initiator),
392 fail_create_channel_(false) {
393 }
394
395 FakeTransport* GetTransport(const std::string& content_name) {
396 return static_cast<FakeTransport*>(
397 BaseSession::GetTransport(content_name));
398 }
399
400 void Connect(FakeSession* dest) {
401 // Simulate the exchange of candidates.
402 CompleteNegotiation();
403 dest->CompleteNegotiation();
404 for (TransportMap::const_iterator it = transport_proxies().begin();
405 it != transport_proxies().end(); ++it) {
406 static_cast<FakeTransport*>(it->second->impl())->SetDestination(
407 dest->GetTransport(it->first));
408 }
409 }
410
411 virtual TransportChannel* CreateChannel(
412 const std::string& content_name,
413 const std::string& channel_name,
414 int component) {
415 if (fail_create_channel_) {
416 return NULL;
417 }
418 return BaseSession::CreateChannel(content_name, channel_name, component);
419 }
420
421 void set_fail_channel_creation(bool fail_channel_creation) {
422 fail_create_channel_ = fail_channel_creation;
423 }
424
425 // TODO: Hoist this into Session when we re-work the Session code.
426 void set_ssl_identity(talk_base::SSLIdentity* identity) {
427 for (TransportMap::const_iterator it = transport_proxies().begin();
428 it != transport_proxies().end(); ++it) {
429 // We know that we have a FakeTransport*
430
431 static_cast<FakeTransport*>(it->second->impl())->set_identity
432 (identity);
433 }
434 }
435
436 protected:
437 virtual Transport* CreateTransport(const std::string& content_name) {
438 return new FakeTransport(signaling_thread(), worker_thread(), content_name);
439 }
440
441 void CompleteNegotiation() {
442 for (TransportMap::const_iterator it = transport_proxies().begin();
443 it != transport_proxies().end(); ++it) {
444 it->second->CompleteNegotiation();
445 it->second->ConnectChannels();
446 }
447 }
448
449 private:
450 bool fail_create_channel_;
451};
452
453} // namespace cricket
454
455#endif // TALK_P2P_BASE_FAKESESSION_H_