- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / base / fakesession.h
1 /*
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/fakesslidentity.h"
37 #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
45 namespace cricket {
46
47 class FakeTransport;
48
49 struct 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.
58 class 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),
71         role_(ICEROLE_UNKNOWN),
72         tiebreaker_(0),
73         ice_proto_(ICEPROTO_HYBRID),
74         remote_ice_mode_(ICEMODE_FULL),
75         dtls_fingerprint_("", NULL, 0),
76         ssl_role_(talk_base::SSL_CLIENT) {
77   }
78   ~FakeTransportChannel() {
79     Reset();
80   }
81
82   uint64 IceTiebreaker() const { return tiebreaker_; }
83   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
101   virtual void SetIceRole(IceRole role) { role_ = role; }
102   virtual IceRole GetIceRole() const { return role_; }
103   virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
104   virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
105   virtual void SetIceCredentials(const std::string& ice_ufrag,
106                                  const std::string& ice_pwd) {
107     ice_ufrag_ = ice_ufrag;
108     ice_pwd_ = ice_pwd;
109   }
110   virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
111                                        const std::string& ice_pwd) {
112     remote_ice_ufrag_ = ice_ufrag;
113     remote_ice_pwd_ = ice_pwd;
114   }
115
116   virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; }
117   virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest,
118                                     size_t digest_len) {
119     dtls_fingerprint_ = talk_base::SSLFingerprint(alg, digest, digest_len);
120     return true;
121   }
122   virtual bool SetSslRole(talk_base::SSLRole role) {
123     ssl_role_ = role;
124     return true;
125   }
126   virtual bool GetSslRole(talk_base::SSLRole* role) const {
127     *role = ssl_role_;
128     return true;
129   }
130
131   virtual void Connect() {
132     if (state_ == STATE_INIT) {
133       state_ = STATE_CONNECTING;
134     }
135   }
136   virtual void Reset() {
137     if (state_ != STATE_INIT) {
138       state_ = STATE_INIT;
139       if (dest_) {
140         dest_->state_ = STATE_INIT;
141         dest_->dest_ = NULL;
142         dest_ = NULL;
143       }
144     }
145   }
146
147   void SetWritable(bool writable) {
148     set_writable(writable);
149   }
150
151   void SetDestination(FakeTransportChannel* dest) {
152     if (state_ == STATE_CONNECTING && dest) {
153       // This simulates the delivery of candidates.
154       dest_ = dest;
155       dest_->dest_ = this;
156       if (identity_ && dest_->identity_) {
157         do_dtls_ = true;
158         dest_->do_dtls_ = true;
159         NegotiateSrtpCiphers();
160       }
161       state_ = STATE_CONNECTED;
162       dest_->state_ = STATE_CONNECTED;
163       set_writable(true);
164       dest_->set_writable(true);
165     } else if (state_ == STATE_CONNECTED && !dest) {
166       // Simulates loss of connectivity, by asymmetrically forgetting dest_.
167       dest_ = NULL;
168       state_ = STATE_CONNECTING;
169       set_writable(false);
170     }
171   }
172
173   virtual int SendPacket(const char* data, size_t len,
174                          talk_base::DiffServCodePoint dscp, int flags) {
175     if (state_ != STATE_CONNECTED) {
176       return -1;
177     }
178
179     if (flags != PF_SRTP_BYPASS && flags != 0) {
180       return -1;
181     }
182
183     PacketMessageData* packet = new PacketMessageData(data, len);
184     if (async_) {
185       talk_base::Thread::Current()->Post(this, 0, packet);
186     } else {
187       talk_base::Thread::Current()->Send(this, 0, packet);
188     }
189     return static_cast<int>(len);
190   }
191   virtual int SetOption(talk_base::Socket::Option opt, int value) {
192     return true;
193   }
194   virtual int GetError() {
195     return 0;
196   }
197
198   virtual void OnSignalingReady() {
199   }
200   virtual void OnCandidate(const Candidate& candidate) {
201   }
202
203   virtual void OnMessage(talk_base::Message* msg) {
204     PacketMessageData* data = static_cast<PacketMessageData*>(
205         msg->pdata);
206     dest_->SignalReadPacket(dest_, data->packet.data(),
207                             data->packet.length(), 0);
208     delete data;
209   }
210
211   bool SetLocalIdentity(talk_base::SSLIdentity* identity) {
212     identity_ = identity;
213     return true;
214   }
215
216
217   void SetRemoteCertificate(talk_base::FakeSSLCertificate* cert) {
218     remote_cert_ = cert;
219   }
220
221   virtual bool IsDtlsActive() const {
222     return do_dtls_;
223   }
224
225   virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) {
226     srtp_ciphers_ = ciphers;
227     return true;
228   }
229
230   virtual bool GetSrtpCipher(std::string* cipher) {
231     if (!chosen_srtp_cipher_.empty()) {
232       *cipher = chosen_srtp_cipher_;
233       return true;
234     }
235     return false;
236   }
237
238   virtual bool GetLocalIdentity(talk_base::SSLIdentity** identity) const {
239     if (!identity_)
240       return false;
241
242     *identity = identity_->GetReference();
243     return true;
244   }
245
246   virtual bool GetRemoteCertificate(talk_base::SSLCertificate** cert) const {
247     if (!remote_cert_)
248       return false;
249
250     *cert = remote_cert_->GetReference();
251     return true;
252   }
253
254   virtual bool ExportKeyingMaterial(const std::string& label,
255                                     const uint8* context,
256                                     size_t context_len,
257                                     bool use_context,
258                                     uint8* result,
259                                     size_t result_len) {
260     if (!chosen_srtp_cipher_.empty()) {
261       memset(result, 0xff, result_len);
262       return true;
263     }
264
265     return false;
266   }
267
268   virtual void NegotiateSrtpCiphers() {
269     for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
270         it1 != srtp_ciphers_.end(); ++it1) {
271       for (std::vector<std::string>::const_iterator it2 =
272               dest_->srtp_ciphers_.begin();
273           it2 != dest_->srtp_ciphers_.end(); ++it2) {
274         if (*it1 == *it2) {
275           chosen_srtp_cipher_ = *it1;
276           dest_->chosen_srtp_cipher_ = *it2;
277           return;
278         }
279       }
280     }
281   }
282
283   virtual bool GetStats(ConnectionInfos* infos) OVERRIDE {
284     ConnectionInfo info;
285     infos->clear();
286     infos->push_back(info);
287     return true;
288   }
289
290  private:
291   enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
292   Transport* transport_;
293   FakeTransportChannel* dest_;
294   State state_;
295   bool async_;
296   talk_base::SSLIdentity* identity_;
297   talk_base::FakeSSLCertificate* remote_cert_;
298   bool do_dtls_;
299   std::vector<std::string> srtp_ciphers_;
300   std::string chosen_srtp_cipher_;
301   IceRole role_;
302   uint64 tiebreaker_;
303   IceProtocolType ice_proto_;
304   std::string ice_ufrag_;
305   std::string ice_pwd_;
306   std::string remote_ice_ufrag_;
307   std::string remote_ice_pwd_;
308   IceMode remote_ice_mode_;
309   talk_base::SSLFingerprint dtls_fingerprint_;
310   talk_base::SSLRole ssl_role_;
311 };
312
313 // Fake transport class, which can be passed to anything that needs a Transport.
314 // Can be informed of another FakeTransport via SetDestination (low-tech way
315 // of doing candidates)
316 class FakeTransport : public Transport {
317  public:
318   typedef std::map<int, FakeTransportChannel*> ChannelMap;
319   FakeTransport(talk_base::Thread* signaling_thread,
320                 talk_base::Thread* worker_thread,
321                 const std::string& content_name,
322                 PortAllocator* alllocator = NULL)
323       : Transport(signaling_thread, worker_thread,
324                   content_name, "test_type", NULL),
325       dest_(NULL),
326       async_(false),
327       identity_(NULL) {
328   }
329   ~FakeTransport() {
330     DestroyAllChannels();
331   }
332
333   const ChannelMap& channels() const { return channels_; }
334
335   void SetAsync(bool async) { async_ = async; }
336   void SetDestination(FakeTransport* dest) {
337     dest_ = dest;
338     for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
339          ++it) {
340       it->second->SetLocalIdentity(identity_);
341       SetChannelDestination(it->first, it->second);
342     }
343   }
344
345   void SetWritable(bool writable) {
346     for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
347          ++it) {
348       it->second->SetWritable(writable);
349     }
350   }
351
352   void set_identity(talk_base::SSLIdentity* identity) {
353     identity_ = identity;
354   }
355
356   using Transport::local_description;
357   using Transport::remote_description;
358
359  protected:
360   virtual TransportChannelImpl* CreateTransportChannel(int component) {
361     if (channels_.find(component) != channels_.end()) {
362       return NULL;
363     }
364     FakeTransportChannel* channel =
365         new FakeTransportChannel(this, content_name(), component);
366     channel->SetAsync(async_);
367     SetChannelDestination(component, channel);
368     channels_[component] = channel;
369     return channel;
370   }
371   virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
372     channels_.erase(channel->component());
373     delete channel;
374   }
375   virtual void SetIdentity_w(talk_base::SSLIdentity* identity) {
376     identity_ = identity;
377   }
378   virtual bool GetIdentity_w(talk_base::SSLIdentity** identity) {
379     if (!identity_)
380       return false;
381
382     *identity = identity_->GetReference();
383     return true;
384   }
385
386  private:
387   FakeTransportChannel* GetFakeChannel(int component) {
388     ChannelMap::iterator it = channels_.find(component);
389     return (it != channels_.end()) ? it->second : NULL;
390   }
391   void SetChannelDestination(int component,
392                              FakeTransportChannel* channel) {
393     FakeTransportChannel* dest_channel = NULL;
394     if (dest_) {
395       dest_channel = dest_->GetFakeChannel(component);
396       if (dest_channel) {
397         dest_channel->SetLocalIdentity(dest_->identity_);
398       }
399     }
400     channel->SetDestination(dest_channel);
401   }
402
403   // Note, this is distinct from the Channel map owned by Transport.
404   // This map just tracks the FakeTransportChannels created by this class.
405   ChannelMap channels_;
406   FakeTransport* dest_;
407   bool async_;
408   talk_base::SSLIdentity* identity_;
409 };
410
411 // Fake session class, which can be passed into a BaseChannel object for
412 // test purposes. Can be connected to other FakeSessions via Connect().
413 class FakeSession : public BaseSession {
414  public:
415   explicit FakeSession()
416       : BaseSession(talk_base::Thread::Current(),
417                     talk_base::Thread::Current(),
418                     NULL, "", "", true),
419       fail_create_channel_(false) {
420   }
421   explicit FakeSession(bool initiator)
422       : BaseSession(talk_base::Thread::Current(),
423                     talk_base::Thread::Current(),
424                     NULL, "", "", initiator),
425       fail_create_channel_(false) {
426   }
427   FakeSession(talk_base::Thread* worker_thread, bool initiator)
428       : BaseSession(talk_base::Thread::Current(),
429                     worker_thread,
430                     NULL, "", "", initiator),
431       fail_create_channel_(false) {
432   }
433
434   FakeTransport* GetTransport(const std::string& content_name) {
435     return static_cast<FakeTransport*>(
436         BaseSession::GetTransport(content_name));
437   }
438
439   void Connect(FakeSession* dest) {
440     // Simulate the exchange of candidates.
441     CompleteNegotiation();
442     dest->CompleteNegotiation();
443     for (TransportMap::const_iterator it = transport_proxies().begin();
444         it != transport_proxies().end(); ++it) {
445       static_cast<FakeTransport*>(it->second->impl())->SetDestination(
446           dest->GetTransport(it->first));
447     }
448   }
449
450   virtual TransportChannel* CreateChannel(
451       const std::string& content_name,
452       const std::string& channel_name,
453       int component) {
454     if (fail_create_channel_) {
455       return NULL;
456     }
457     return BaseSession::CreateChannel(content_name, channel_name, component);
458   }
459
460   void set_fail_channel_creation(bool fail_channel_creation) {
461     fail_create_channel_ = fail_channel_creation;
462   }
463
464   // TODO: Hoist this into Session when we re-work the Session code.
465   void set_ssl_identity(talk_base::SSLIdentity* identity) {
466     for (TransportMap::const_iterator it = transport_proxies().begin();
467         it != transport_proxies().end(); ++it) {
468       // We know that we have a FakeTransport*
469
470       static_cast<FakeTransport*>(it->second->impl())->set_identity
471           (identity);
472     }
473   }
474
475  protected:
476   virtual Transport* CreateTransport(const std::string& content_name) {
477     return new FakeTransport(signaling_thread(), worker_thread(), content_name);
478   }
479
480   void CompleteNegotiation() {
481     for (TransportMap::const_iterator it = transport_proxies().begin();
482         it != transport_proxies().end(); ++it) {
483       it->second->CompleteNegotiation();
484       it->second->ConnectChannels();
485     }
486   }
487
488  private:
489   bool fail_create_channel_;
490 };
491
492 }  // namespace cricket
493
494 #endif  // TALK_P2P_BASE_FAKESESSION_H_