blob: d19944994583a42c3cc076ac202ddb6e49a0856b [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"
wu@webrtc.org4551b792013-10-09 15:37:36 +000036#include "talk/base/fakesslidentity.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037#include "talk/base/sigslot.h"
38#include "talk/base/sslfingerprint.h"
39#include "talk/base/messagequeue.h"
40#include "talk/p2p/base/session.h"
41#include "talk/p2p/base/transport.h"
42#include "talk/p2p/base/transportchannel.h"
43#include "talk/p2p/base/transportchannelimpl.h"
44
45namespace cricket {
46
47class FakeTransport;
48
49struct PacketMessageData : public talk_base::MessageData {
50 PacketMessageData(const char* data, size_t len) : packet(data, len) {
51 }
52 talk_base::Buffer packet;
53};
54
55// Fake transport channel class, which can be passed to anything that needs a
56// transport channel. Can be informed of another FakeTransportChannel via
57// SetDestination.
58class FakeTransportChannel : public TransportChannelImpl,
59 public talk_base::MessageHandler {
60 public:
61 explicit FakeTransportChannel(Transport* transport,
62 const std::string& content_name,
63 int component)
64 : TransportChannelImpl(content_name, component),
65 transport_(transport),
66 dest_(NULL),
67 state_(STATE_INIT),
68 async_(false),
69 identity_(NULL),
70 do_dtls_(false),
mallinath@webrtc.orga5506692013-08-12 21:18:15 +000071 role_(ICEROLE_UNKNOWN),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072 tiebreaker_(0),
73 ice_proto_(ICEPROTO_HYBRID),
74 remote_ice_mode_(ICEMODE_FULL),
mallinath@webrtc.orgaf84d782013-08-26 17:14:13 +000075 dtls_fingerprint_("", NULL, 0),
76 ssl_role_(talk_base::SSL_CLIENT) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077 }
78 ~FakeTransportChannel() {
79 Reset();
80 }
81
mallinath@webrtc.orga5506692013-08-12 21:18:15 +000082 uint64 IceTiebreaker() const { return tiebreaker_; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083 TransportProtocol protocol() const { return ice_proto_; }
84 IceMode remote_ice_mode() const { return remote_ice_mode_; }
85 const std::string& ice_ufrag() const { return ice_ufrag_; }
86 const std::string& ice_pwd() const { return ice_pwd_; }
87 const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; }
88 const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
89 const talk_base::SSLFingerprint& dtls_fingerprint() const {
90 return dtls_fingerprint_;
91 }
92
93 void SetAsync(bool async) {
94 async_ = async;
95 }
96
97 virtual Transport* GetTransport() {
98 return transport_;
99 }
100
mallinath@webrtc.orga5506692013-08-12 21:18:15 +0000101 virtual void SetIceRole(IceRole role) { role_ = role; }
102 virtual IceRole GetIceRole() const { return role_; }
103 virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000104 virtual bool GetIceProtocolType(IceProtocolType* type) const {
105 *type = ice_proto_;
106 return true;
107 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108 virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
109 virtual void SetIceCredentials(const std::string& ice_ufrag,
110 const std::string& ice_pwd) {
111 ice_ufrag_ = ice_ufrag;
112 ice_pwd_ = ice_pwd;
113 }
114 virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
115 const std::string& ice_pwd) {
116 remote_ice_ufrag_ = ice_ufrag;
117 remote_ice_pwd_ = ice_pwd;
118 }
119
120 virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; }
121 virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest,
122 size_t digest_len) {
123 dtls_fingerprint_ = talk_base::SSLFingerprint(alg, digest, digest_len);
124 return true;
125 }
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000126 virtual bool SetSslRole(talk_base::SSLRole role) {
127 ssl_role_ = role;
128 return true;
129 }
130 virtual bool GetSslRole(talk_base::SSLRole* role) const {
131 *role = ssl_role_;
132 return true;
133 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
135 virtual void Connect() {
136 if (state_ == STATE_INIT) {
137 state_ = STATE_CONNECTING;
138 }
139 }
140 virtual void Reset() {
141 if (state_ != STATE_INIT) {
142 state_ = STATE_INIT;
143 if (dest_) {
144 dest_->state_ = STATE_INIT;
145 dest_->dest_ = NULL;
146 dest_ = NULL;
147 }
148 }
149 }
150
151 void SetWritable(bool writable) {
152 set_writable(writable);
153 }
154
155 void SetDestination(FakeTransportChannel* dest) {
156 if (state_ == STATE_CONNECTING && dest) {
157 // This simulates the delivery of candidates.
158 dest_ = dest;
159 dest_->dest_ = this;
160 if (identity_ && dest_->identity_) {
161 do_dtls_ = true;
162 dest_->do_dtls_ = true;
163 NegotiateSrtpCiphers();
164 }
165 state_ = STATE_CONNECTED;
166 dest_->state_ = STATE_CONNECTED;
167 set_writable(true);
168 dest_->set_writable(true);
169 } else if (state_ == STATE_CONNECTED && !dest) {
170 // Simulates loss of connectivity, by asymmetrically forgetting dest_.
171 dest_ = NULL;
172 state_ = STATE_CONNECTING;
173 set_writable(false);
174 }
175 }
176
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000177 virtual int SendPacket(const char* data, size_t len,
178 talk_base::DiffServCodePoint dscp, int flags) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179 if (state_ != STATE_CONNECTED) {
180 return -1;
181 }
182
183 if (flags != PF_SRTP_BYPASS && flags != 0) {
184 return -1;
185 }
186
187 PacketMessageData* packet = new PacketMessageData(data, len);
188 if (async_) {
189 talk_base::Thread::Current()->Post(this, 0, packet);
190 } else {
191 talk_base::Thread::Current()->Send(this, 0, packet);
192 }
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000193 return static_cast<int>(len);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000194 }
195 virtual int SetOption(talk_base::Socket::Option opt, int value) {
196 return true;
197 }
198 virtual int GetError() {
199 return 0;
200 }
201
202 virtual void OnSignalingReady() {
203 }
204 virtual void OnCandidate(const Candidate& candidate) {
205 }
206
207 virtual void OnMessage(talk_base::Message* msg) {
208 PacketMessageData* data = static_cast<PacketMessageData*>(
209 msg->pdata);
210 dest_->SignalReadPacket(dest_, data->packet.data(),
wu@webrtc.orga9890802013-12-13 00:21:03 +0000211 data->packet.length(),
212 talk_base::CreatePacketTime(0), 0);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213 delete data;
214 }
215
216 bool SetLocalIdentity(talk_base::SSLIdentity* identity) {
217 identity_ = identity;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218 return true;
219 }
220
wu@webrtc.org4551b792013-10-09 15:37:36 +0000221
222 void SetRemoteCertificate(talk_base::FakeSSLCertificate* cert) {
223 remote_cert_ = cert;
224 }
225
226 virtual bool IsDtlsActive() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227 return do_dtls_;
228 }
229
wu@webrtc.org4551b792013-10-09 15:37:36 +0000230 virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231 srtp_ciphers_ = ciphers;
232 return true;
233 }
234
235 virtual bool GetSrtpCipher(std::string* cipher) {
236 if (!chosen_srtp_cipher_.empty()) {
237 *cipher = chosen_srtp_cipher_;
238 return true;
239 }
240 return false;
241 }
242
wu@webrtc.org4551b792013-10-09 15:37:36 +0000243 virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const {
244 if (!identity_)
245 return false;
246
247 *identity = identity_->GetReference();
248 return true;
249 }
250
251 virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const {
252 if (!remote_cert_)
253 return false;
254
255 *cert = remote_cert_->GetReference();
256 return true;
257 }
258
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 virtual bool ExportKeyingMaterial(const std::string& label,
260 const uint8* context,
261 size_t context_len,
262 bool use_context,
263 uint8* result,
264 size_t result_len) {
265 if (!chosen_srtp_cipher_.empty()) {
266 memset(result, 0xff, result_len);
267 return true;
268 }
269
270 return false;
271 }
272
273 virtual void NegotiateSrtpCiphers() {
274 for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
275 it1 != srtp_ciphers_.end(); ++it1) {
276 for (std::vector<std::string>::const_iterator it2 =
277 dest_->srtp_ciphers_.begin();
278 it2 != dest_->srtp_ciphers_.end(); ++it2) {
279 if (*it1 == *it2) {
280 chosen_srtp_cipher_ = *it1;
281 dest_->chosen_srtp_cipher_ = *it2;
282 return;
283 }
284 }
285 }
286 }
287
288 virtual bool GetStats(ConnectionInfos* infos) OVERRIDE {
289 ConnectionInfo info;
290 infos->clear();
291 infos->push_back(info);
292 return true;
293 }
294
295 private:
296 enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
297 Transport* transport_;
298 FakeTransportChannel* dest_;
299 State state_;
300 bool async_;
301 talk_base::SSLIdentity* identity_;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000302 talk_base::FakeSSLCertificate* remote_cert_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000303 bool do_dtls_;
304 std::vector<std::string> srtp_ciphers_;
305 std::string chosen_srtp_cipher_;
mallinath@webrtc.orga5506692013-08-12 21:18:15 +0000306 IceRole role_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 uint64 tiebreaker_;
308 IceProtocolType ice_proto_;
309 std::string ice_ufrag_;
310 std::string ice_pwd_;
311 std::string remote_ice_ufrag_;
312 std::string remote_ice_pwd_;
313 IceMode remote_ice_mode_;
314 talk_base::SSLFingerprint dtls_fingerprint_;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000315 talk_base::SSLRole ssl_role_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000316};
317
318// Fake transport class, which can be passed to anything that needs a Transport.
319// Can be informed of another FakeTransport via SetDestination (low-tech way
320// of doing candidates)
321class FakeTransport : public Transport {
322 public:
323 typedef std::map<int, FakeTransportChannel*> ChannelMap;
324 FakeTransport(talk_base::Thread* signaling_thread,
325 talk_base::Thread* worker_thread,
326 const std::string& content_name,
327 PortAllocator* alllocator = NULL)
328 : Transport(signaling_thread, worker_thread,
329 content_name, "test_type", NULL),
330 dest_(NULL),
331 async_(false),
332 identity_(NULL) {
333 }
334 ~FakeTransport() {
335 DestroyAllChannels();
336 }
337
338 const ChannelMap& channels() const { return channels_; }
339
340 void SetAsync(bool async) { async_ = async; }
341 void SetDestination(FakeTransport* dest) {
342 dest_ = dest;
343 for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
344 ++it) {
345 it->second->SetLocalIdentity(identity_);
346 SetChannelDestination(it->first, it->second);
347 }
348 }
349
350 void SetWritable(bool writable) {
351 for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
352 ++it) {
353 it->second->SetWritable(writable);
354 }
355 }
356
357 void set_identity(talk_base::SSLIdentity* identity) {
358 identity_ = identity;
359 }
360
361 using Transport::local_description;
362 using Transport::remote_description;
363
364 protected:
365 virtual TransportChannelImpl* CreateTransportChannel(int component) {
366 if (channels_.find(component) != channels_.end()) {
367 return NULL;
368 }
369 FakeTransportChannel* channel =
370 new FakeTransportChannel(this, content_name(), component);
371 channel->SetAsync(async_);
372 SetChannelDestination(component, channel);
373 channels_[component] = channel;
374 return channel;
375 }
376 virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
377 channels_.erase(channel->component());
378 delete channel;
379 }
wu@webrtc.org4551b792013-10-09 15:37:36 +0000380 virtual void SetIdentity_w(talk_base::SSLIdentity* identity) {
381 identity_ = identity;
382 }
383 virtual bool GetIdentity_w(talk_base::SSLIdentity** identity) {
384 if (!identity_)
385 return false;
386
387 *identity = identity_->GetReference();
388 return true;
389 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390
391 private:
392 FakeTransportChannel* GetFakeChannel(int component) {
393 ChannelMap::iterator it = channels_.find(component);
394 return (it != channels_.end()) ? it->second : NULL;
395 }
396 void SetChannelDestination(int component,
397 FakeTransportChannel* channel) {
398 FakeTransportChannel* dest_channel = NULL;
399 if (dest_) {
400 dest_channel = dest_->GetFakeChannel(component);
401 if (dest_channel) {
402 dest_channel->SetLocalIdentity(dest_->identity_);
403 }
404 }
405 channel->SetDestination(dest_channel);
406 }
407
408 // Note, this is distinct from the Channel map owned by Transport.
409 // This map just tracks the FakeTransportChannels created by this class.
410 ChannelMap channels_;
411 FakeTransport* dest_;
412 bool async_;
413 talk_base::SSLIdentity* identity_;
414};
415
416// Fake session class, which can be passed into a BaseChannel object for
417// test purposes. Can be connected to other FakeSessions via Connect().
418class FakeSession : public BaseSession {
419 public:
420 explicit FakeSession()
421 : BaseSession(talk_base::Thread::Current(),
422 talk_base::Thread::Current(),
423 NULL, "", "", true),
424 fail_create_channel_(false) {
425 }
426 explicit FakeSession(bool initiator)
427 : BaseSession(talk_base::Thread::Current(),
428 talk_base::Thread::Current(),
429 NULL, "", "", initiator),
430 fail_create_channel_(false) {
431 }
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +0000432 FakeSession(talk_base::Thread* worker_thread, bool initiator)
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000433 : BaseSession(talk_base::Thread::Current(),
434 worker_thread,
435 NULL, "", "", initiator),
436 fail_create_channel_(false) {
437 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438
439 FakeTransport* GetTransport(const std::string& content_name) {
440 return static_cast<FakeTransport*>(
441 BaseSession::GetTransport(content_name));
442 }
443
444 void Connect(FakeSession* dest) {
445 // Simulate the exchange of candidates.
446 CompleteNegotiation();
447 dest->CompleteNegotiation();
448 for (TransportMap::const_iterator it = transport_proxies().begin();
449 it != transport_proxies().end(); ++it) {
450 static_cast<FakeTransport*>(it->second->impl())->SetDestination(
451 dest->GetTransport(it->first));
452 }
453 }
454
455 virtual TransportChannel* CreateChannel(
456 const std::string& content_name,
457 const std::string& channel_name,
458 int component) {
459 if (fail_create_channel_) {
460 return NULL;
461 }
462 return BaseSession::CreateChannel(content_name, channel_name, component);
463 }
464
465 void set_fail_channel_creation(bool fail_channel_creation) {
466 fail_create_channel_ = fail_channel_creation;
467 }
468
469 // TODO: Hoist this into Session when we re-work the Session code.
470 void set_ssl_identity(talk_base::SSLIdentity* identity) {
471 for (TransportMap::const_iterator it = transport_proxies().begin();
472 it != transport_proxies().end(); ++it) {
473 // We know that we have a FakeTransport*
474
475 static_cast<FakeTransport*>(it->second->impl())->set_identity
476 (identity);
477 }
478 }
479
480 protected:
481 virtual Transport* CreateTransport(const std::string& content_name) {
482 return new FakeTransport(signaling_thread(), worker_thread(), content_name);
483 }
484
485 void CompleteNegotiation() {
486 for (TransportMap::const_iterator it = transport_proxies().begin();
487 it != transport_proxies().end(); ++it) {
488 it->second->CompleteNegotiation();
489 it->second->ConnectChannels();
490 }
491 }
492
493 private:
494 bool fail_create_channel_;
495};
496
497} // namespace cricket
498
499#endif // TALK_P2P_BASE_FAKESESSION_H_