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