1 /* 2 * libjingle 3 * Copyright 2011 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 #include "talk/base/fakesslidentity.h" 29 #include "talk/base/gunit.h" 30 #include "talk/base/thread.h" 31 #include "talk/p2p/base/constants.h" 32 #include "talk/p2p/base/fakesession.h" 33 #include "talk/p2p/base/parsing.h" 34 #include "talk/p2p/base/p2ptransport.h" 35 #include "talk/p2p/base/rawtransport.h" 36 #include "talk/p2p/base/sessionmessages.h" 37 #include "talk/xmllite/xmlelement.h" 38 #include "talk/xmpp/constants.h" 39 40 using cricket::Candidate; 41 using cricket::Candidates; 42 using cricket::Transport; 43 using cricket::FakeTransport; 44 using cricket::TransportChannel; 45 using cricket::FakeTransportChannel; 46 using cricket::IceRole; 47 using cricket::TransportDescription; 48 using cricket::WriteError; 49 using cricket::ParseError; 50 using talk_base::SocketAddress; 51 52 static const char kIceUfrag1[] = "TESTICEUFRAG0001"; 53 static const char kIcePwd1[] = "TESTICEPWD00000000000001"; 54 55 class TransportTest : public testing::Test, 56 public sigslot::has_slots<> { 57 public: 58 TransportTest() 59 : thread_(talk_base::Thread::Current()), 60 transport_(new FakeTransport( 61 thread_, thread_, "test content name", NULL)), 62 channel_(NULL), 63 connecting_signalled_(false) { 64 transport_->SignalConnecting.connect(this, &TransportTest::OnConnecting); 65 } 66 ~TransportTest() { 67 transport_->DestroyAllChannels(); 68 } 69 bool SetupChannel() { 70 channel_ = CreateChannel(1); 71 return (channel_ != NULL); 72 } 73 FakeTransportChannel* CreateChannel(int component) { 74 return static_cast<FakeTransportChannel*>( 75 transport_->CreateChannel(component)); 76 } 77 void DestroyChannel() { 78 transport_->DestroyChannel(1); 79 channel_ = NULL; 80 } 81 82 protected: 83 void OnConnecting(Transport* transport) { 84 connecting_signalled_ = true; 85 } 86 87 talk_base::Thread* thread_; 88 talk_base::scoped_ptr<FakeTransport> transport_; 89 FakeTransportChannel* channel_; 90 bool connecting_signalled_; 91 }; 92 93 class FakeCandidateTranslator : public cricket::CandidateTranslator { 94 public: 95 void AddMapping(int component, const std::string& channel_name) { 96 name_to_component[channel_name] = component; 97 component_to_name[component] = channel_name; 98 } 99 100 bool GetChannelNameFromComponent( 101 int component, std::string* channel_name) const { 102 if (component_to_name.find(component) == component_to_name.end()) { 103 return false; 104 } 105 *channel_name = component_to_name.find(component)->second; 106 return true; 107 } 108 bool GetComponentFromChannelName( 109 const std::string& channel_name, int* component) const { 110 if (name_to_component.find(channel_name) == name_to_component.end()) { 111 return false; 112 } 113 *component = name_to_component.find(channel_name)->second; 114 return true; 115 } 116 117 std::map<std::string, int> name_to_component; 118 std::map<int, std::string> component_to_name; 119 }; 120 121 // Test that calling ConnectChannels triggers an OnConnecting signal. 122 TEST_F(TransportTest, TestConnectChannelsDoesSignal) { 123 EXPECT_TRUE(SetupChannel()); 124 transport_->ConnectChannels(); 125 EXPECT_FALSE(connecting_signalled_); 126 127 EXPECT_TRUE_WAIT(connecting_signalled_, 100); 128 } 129 130 // Test that DestroyAllChannels kills any pending OnConnecting signals. 131 TEST_F(TransportTest, TestDestroyAllClearsPosts) { 132 EXPECT_TRUE(transport_->CreateChannel(1) != NULL); 133 134 transport_->ConnectChannels(); 135 transport_->DestroyAllChannels(); 136 137 thread_->ProcessMessages(0); 138 EXPECT_FALSE(connecting_signalled_); 139 } 140 141 // This test verifies channels are created with proper ICE 142 // role, tiebreaker and remote ice mode and credentials after offer and 143 // answer negotiations. 144 TEST_F(TransportTest, TestChannelIceParameters) { 145 transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); 146 transport_->SetIceTiebreaker(99U); 147 cricket::TransportDescription local_desc( 148 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 149 kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, NULL, cricket::Candidates()); 150 ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, 151 cricket::CA_OFFER)); 152 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); 153 EXPECT_TRUE(SetupChannel()); 154 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); 155 EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); 156 EXPECT_EQ(kIceUfrag1, channel_->ice_ufrag()); 157 EXPECT_EQ(kIcePwd1, channel_->ice_pwd()); 158 159 cricket::TransportDescription remote_desc( 160 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 161 kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, NULL, cricket::Candidates()); 162 ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, 163 cricket::CA_ANSWER)); 164 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); 165 EXPECT_EQ(99U, channel_->IceTiebreaker()); 166 EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); 167 // Changing the transport role from CONTROLLING to CONTROLLED. 168 transport_->SetIceRole(cricket::ICEROLE_CONTROLLED); 169 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel_->GetIceRole()); 170 EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); 171 EXPECT_EQ(kIceUfrag1, channel_->remote_ice_ufrag()); 172 EXPECT_EQ(kIcePwd1, channel_->remote_ice_pwd()); 173 } 174 175 // Tests channel role is reversed after receiving ice-lite from remote. 176 TEST_F(TransportTest, TestSetRemoteIceLiteInOffer) { 177 transport_->SetIceRole(cricket::ICEROLE_CONTROLLED); 178 cricket::TransportDescription remote_desc( 179 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 180 kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE, NULL, cricket::Candidates()); 181 ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, 182 cricket::CA_OFFER)); 183 cricket::TransportDescription local_desc( 184 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 185 kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, NULL, cricket::Candidates()); 186 ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, 187 cricket::CA_ANSWER)); 188 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); 189 EXPECT_TRUE(SetupChannel()); 190 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); 191 EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode()); 192 } 193 194 // Tests ice-lite in remote answer. 195 TEST_F(TransportTest, TestSetRemoteIceLiteInAnswer) { 196 transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); 197 cricket::TransportDescription local_desc( 198 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 199 kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL, NULL, cricket::Candidates()); 200 ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, 201 cricket::CA_OFFER)); 202 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); 203 EXPECT_TRUE(SetupChannel()); 204 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); 205 // Channels will be created in ICEFULL_MODE. 206 EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); 207 cricket::TransportDescription remote_desc( 208 cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), 209 kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE, NULL, cricket::Candidates()); 210 ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, 211 cricket::CA_ANSWER)); 212 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); 213 // After receiving remote description with ICEMODE_LITE, channel should 214 // have mode set to ICEMODE_LITE. 215 EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode()); 216 } 217 218 // Tests that we can properly serialize/deserialize candidates. 219 TEST_F(TransportTest, TestP2PTransportWriteAndParseCandidate) { 220 Candidate test_candidate( 221 "", 1, "udp", 222 talk_base::SocketAddress("2001:db8:fefe::1", 9999), 223 738197504, "abcdef", "ghijkl", "foo", "testnet", 50, ""); 224 Candidate test_candidate2( 225 "", 2, "tcp", 226 talk_base::SocketAddress("192.168.7.1", 9999), 227 1107296256, "mnopqr", "stuvwx", "bar", "testnet2", 100, ""); 228 talk_base::SocketAddress host_address("www.google.com", 24601); 229 host_address.SetResolvedIP(talk_base::IPAddress(0x0A000001)); 230 Candidate test_candidate3( 231 "", 3, "spdy", host_address, 1476395008, "yzabcd", 232 "efghij", "baz", "testnet3", 150, ""); 233 WriteError write_error; 234 ParseError parse_error; 235 talk_base::scoped_ptr<buzz::XmlElement> elem; 236 cricket::Candidate parsed_candidate; 237 cricket::P2PTransportParser parser; 238 239 FakeCandidateTranslator translator; 240 translator.AddMapping(1, "test"); 241 translator.AddMapping(2, "test2"); 242 translator.AddMapping(3, "test3"); 243 244 EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate, &translator, 245 elem.accept(), &write_error)); 246 EXPECT_EQ("", write_error.text); 247 EXPECT_EQ("test", elem->Attr(buzz::QN_NAME)); 248 EXPECT_EQ("udp", elem->Attr(cricket::QN_PROTOCOL)); 249 EXPECT_EQ("2001:db8:fefe::1", elem->Attr(cricket::QN_ADDRESS)); 250 EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); 251 EXPECT_EQ("0.34", elem->Attr(cricket::QN_PREFERENCE)); 252 EXPECT_EQ("abcdef", elem->Attr(cricket::QN_USERNAME)); 253 EXPECT_EQ("ghijkl", elem->Attr(cricket::QN_PASSWORD)); 254 EXPECT_EQ("foo", elem->Attr(cricket::QN_TYPE)); 255 EXPECT_EQ("testnet", elem->Attr(cricket::QN_NETWORK)); 256 EXPECT_EQ("50", elem->Attr(cricket::QN_GENERATION)); 257 258 EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, 259 &parsed_candidate, &parse_error)); 260 EXPECT_TRUE(test_candidate.IsEquivalent(parsed_candidate)); 261 262 EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate2, &translator, 263 elem.accept(), &write_error)); 264 EXPECT_EQ("test2", elem->Attr(buzz::QN_NAME)); 265 EXPECT_EQ("tcp", elem->Attr(cricket::QN_PROTOCOL)); 266 EXPECT_EQ("192.168.7.1", elem->Attr(cricket::QN_ADDRESS)); 267 EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); 268 EXPECT_EQ("0.51", elem->Attr(cricket::QN_PREFERENCE)); 269 EXPECT_EQ("mnopqr", elem->Attr(cricket::QN_USERNAME)); 270 EXPECT_EQ("stuvwx", elem->Attr(cricket::QN_PASSWORD)); 271 EXPECT_EQ("bar", elem->Attr(cricket::QN_TYPE)); 272 EXPECT_EQ("testnet2", elem->Attr(cricket::QN_NETWORK)); 273 EXPECT_EQ("100", elem->Attr(cricket::QN_GENERATION)); 274 275 EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, 276 &parsed_candidate, &parse_error)); 277 EXPECT_TRUE(test_candidate2.IsEquivalent(parsed_candidate)); 278 279 // Check that an ip is preferred over hostname. 280 EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate3, &translator, 281 elem.accept(), &write_error)); 282 EXPECT_EQ("test3", elem->Attr(cricket::QN_NAME)); 283 EXPECT_EQ("spdy", elem->Attr(cricket::QN_PROTOCOL)); 284 EXPECT_EQ("10.0.0.1", elem->Attr(cricket::QN_ADDRESS)); 285 EXPECT_EQ("24601", elem->Attr(cricket::QN_PORT)); 286 EXPECT_EQ("0.69", elem->Attr(cricket::QN_PREFERENCE)); 287 EXPECT_EQ("yzabcd", elem->Attr(cricket::QN_USERNAME)); 288 EXPECT_EQ("efghij", elem->Attr(cricket::QN_PASSWORD)); 289 EXPECT_EQ("baz", elem->Attr(cricket::QN_TYPE)); 290 EXPECT_EQ("testnet3", elem->Attr(cricket::QN_NETWORK)); 291 EXPECT_EQ("150", elem->Attr(cricket::QN_GENERATION)); 292 293 EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, 294 &parsed_candidate, &parse_error)); 295 EXPECT_TRUE(test_candidate3.IsEquivalent(parsed_candidate)); 296 } 297 298 TEST_F(TransportTest, TestGetStats) { 299 EXPECT_TRUE(SetupChannel()); 300 cricket::TransportStats stats; 301 EXPECT_TRUE(transport_->GetStats(&stats)); 302 // Note that this tests the behavior of a FakeTransportChannel. 303 ASSERT_EQ(1U, stats.channel_stats.size()); 304 EXPECT_EQ(1, stats.channel_stats[0].component); 305 transport_->ConnectChannels(); 306 EXPECT_TRUE(transport_->GetStats(&stats)); 307 ASSERT_EQ(1U, stats.channel_stats.size()); 308 EXPECT_EQ(1, stats.channel_stats[0].component); 309 } 310