OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <string.h> | |
12 | |
13 #include <deque> | |
14 #include <map> | |
15 #include <sstream> | |
16 | |
17 #include "webrtc/base/base64.h" | |
18 #include "webrtc/base/common.h" | |
19 #include "webrtc/base/gunit.h" | |
20 #include "webrtc/base/helpers.h" | |
21 #include "webrtc/base/logging.h" | |
22 #include "webrtc/base/natserver.h" | |
23 #include "webrtc/base/natsocketfactory.h" | |
24 #include "webrtc/base/stringencode.h" | |
25 #include "webrtc/libjingle/session/parsing.h" | |
26 #include "webrtc/libjingle/session/sessionclient.h" | |
27 #include "webrtc/libjingle/session/sessionmanager.h" | |
28 #include "webrtc/libjingle/xmpp/constants.h" | |
29 #include "webrtc/p2p/base/basicpacketsocketfactory.h" | |
30 #include "webrtc/p2p/base/constants.h" | |
31 #include "webrtc/p2p/base/p2ptransport.h" | |
32 #include "webrtc/p2p/base/portallocator.h" | |
33 #include "webrtc/p2p/base/relayport.h" | |
34 #include "webrtc/p2p/base/relayserver.h" | |
35 #include "webrtc/p2p/base/stunport.h" | |
36 #include "webrtc/p2p/base/stunserver.h" | |
37 #include "webrtc/p2p/base/transportchannel.h" | |
38 #include "webrtc/p2p/base/transportchannelproxy.h" | |
39 #include "webrtc/p2p/base/udpport.h" | |
40 | |
41 using cricket::SignalingProtocol; | |
42 using cricket::PROTOCOL_HYBRID; | |
43 using cricket::PROTOCOL_JINGLE; | |
44 using cricket::PROTOCOL_GINGLE; | |
45 | |
46 static const std::string kInitiator = "init@init.com"; | |
47 static const std::string kResponder = "resp@resp.com"; | |
48 // Expected from test random number generator. | |
49 static const std::string kSessionId = "9254631414740579489"; | |
50 // TODO: When we need to test more than one transport type, | |
51 // allow this to be injected like the content types are. | |
52 static const std::string kTransportType = "http://www.google.com/transport/p2p"; | |
53 | |
54 // Controls how long we wait for a session to send messages that we | |
55 // expect, in milliseconds. We put it high to avoid flaky tests. | |
56 static const int kEventTimeout = 5000; | |
57 | |
58 static const int kNumPorts = 2; | |
59 static const int kPort0 = 28653; | |
60 static const int kPortStep = 5; | |
61 | |
62 int GetPort(int port_index) { | |
63 return kPort0 + (port_index * kPortStep); | |
64 } | |
65 | |
66 std::string GetPortString(int port_index) { | |
67 return rtc::ToString(GetPort(port_index)); | |
68 } | |
69 | |
70 // Only works for port_index < 10, which is fine for our purposes. | |
71 std::string GetUsername(int port_index) { | |
72 return "username" + std::string(8, rtc::ToString(port_index)[0]); | |
73 } | |
74 | |
75 // Only works for port_index < 10, which is fine for our purposes. | |
76 std::string GetPassword(int port_index) { | |
77 return "password" + std::string(8, rtc::ToString(port_index)[0]); | |
78 } | |
79 | |
80 std::string IqAck(const std::string& id, | |
81 const std::string& from, | |
82 const std::string& to) { | |
83 return "<cli:iq" | |
84 " to=\"" + to + "\"" | |
85 " id=\"" + id + "\"" | |
86 " type=\"result\"" | |
87 " from=\"" + from + "\"" | |
88 " xmlns:cli=\"jabber:client\"" | |
89 "/>"; | |
90 } | |
91 | |
92 std::string IqSet(const std::string& id, | |
93 const std::string& from, | |
94 const std::string& to, | |
95 const std::string& content) { | |
96 return "<cli:iq" | |
97 " to=\"" + to + "\"" | |
98 " type=\"set\"" | |
99 " from=\"" + from + "\"" | |
100 " id=\"" + id + "\"" | |
101 " xmlns:cli=\"jabber:client\"" | |
102 ">" | |
103 + content + | |
104 "</cli:iq>"; | |
105 } | |
106 | |
107 std::string IqError(const std::string& id, | |
108 const std::string& from, | |
109 const std::string& to, | |
110 const std::string& content) { | |
111 return "<cli:error" | |
112 " to=\"" + to + "\"" | |
113 " type=\"error\"" | |
114 " from=\"" + from + "\"" | |
115 " id=\"" + id + "\"" | |
116 " xmlns:cli=\"jabber:client\"" | |
117 ">" | |
118 + content + | |
119 "</cli:error>"; | |
120 } | |
121 | |
122 std::string GingleSessionXml(const std::string& type, | |
123 const std::string& content) { | |
124 return "<session" | |
125 " xmlns=\"http://www.google.com/session\"" | |
126 " type=\"" + type + "\"" | |
127 " id=\"" + kSessionId + "\"" | |
128 " initiator=\"" + kInitiator + "\"" | |
129 ">" | |
130 + content + | |
131 "</session>"; | |
132 } | |
133 | |
134 std::string GingleDescriptionXml(const std::string& content_type) { | |
135 return "<description" | |
136 " xmlns=\"" + content_type + "\"" | |
137 "/>"; | |
138 } | |
139 | |
140 std::string P2pCandidateXml(const std::string& name, int port_index) { | |
141 // Port will update the rtcp username by +1 on the last character. So we need | |
142 // to compensate here. See Port::username_fragment() for detail. | |
143 std::string username = GetUsername(port_index); | |
144 // TODO: Use the component id instead of the channel name to | |
145 // determinte if we need to covert the username here. | |
146 if (name == "rtcp" || name == "video_rtcp" || name == "chanb") { | |
147 char next_ch = username[username.size() - 1]; | |
148 ASSERT(username.size() > 0); | |
149 rtc::Base64::GetNextBase64Char(next_ch, &next_ch); | |
150 username[username.size() - 1] = next_ch; | |
151 } | |
152 return "<candidate" | |
153 " name=\"" + name + "\"" | |
154 " address=\"127.0.0.1\"" | |
155 " port=\"" + GetPortString(port_index) + "\"" | |
156 " preference=\"0.99\"" | |
157 " username=\"" + username + "\"" | |
158 " protocol=\"udp\"" | |
159 " generation=\"0\"" | |
160 " password=\"" + GetPassword(port_index) + "\"" | |
161 " type=\"local\"" | |
162 " network=\"network\"" | |
163 "/>"; | |
164 } | |
165 | |
166 std::string JingleActionXml(const std::string& action, | |
167 const std::string& content) { | |
168 return "<jingle" | |
169 " xmlns=\"urn:xmpp:jingle:1\"" | |
170 " action=\"" + action + "\"" | |
171 " sid=\"" + kSessionId + "\"" | |
172 ">" | |
173 + content + | |
174 "</jingle>"; | |
175 } | |
176 | |
177 std::string JingleInitiateActionXml(const std::string& content) { | |
178 return "<jingle" | |
179 " xmlns=\"urn:xmpp:jingle:1\"" | |
180 " action=\"session-initiate\"" | |
181 " sid=\"" + kSessionId + "\"" | |
182 " initiator=\"" + kInitiator + "\"" | |
183 ">" | |
184 + content + | |
185 "</jingle>"; | |
186 } | |
187 | |
188 std::string JingleGroupInfoXml(const std::string& content_name_a, | |
189 const std::string& content_name_b) { | |
190 std::string group_info = "<jin:group" | |
191 " type=\"BUNDLE\"" | |
192 " xmlns:jin=\"google:jingle\"" | |
193 ">"; | |
194 if (!content_name_a.empty()) | |
195 group_info += "<content name=\"" + content_name_a + "\"" | |
196 "/>"; | |
197 if (!content_name_b.empty()) | |
198 group_info += "<content name=\"" + content_name_b + "\"" | |
199 "/>"; | |
200 group_info += "</jin:group>"; | |
201 return group_info; | |
202 } | |
203 | |
204 | |
205 std::string JingleEmptyContentXml(const std::string& content_name, | |
206 const std::string& content_type, | |
207 const std::string& transport_type) { | |
208 return "<content" | |
209 " name=\"" + content_name + "\"" | |
210 " creator=\"initiator\"" | |
211 ">" | |
212 "<description" | |
213 " xmlns=\"" + content_type + "\"" | |
214 "/>" | |
215 "<transport" | |
216 " xmlns=\"" + transport_type + "\"" | |
217 "/>" | |
218 "</content>"; | |
219 } | |
220 | |
221 std::string JingleContentXml(const std::string& content_name, | |
222 const std::string& content_type, | |
223 const std::string& transport_type, | |
224 const std::string& transport_main) { | |
225 std::string transport = transport_type.empty() ? "" : | |
226 "<transport" | |
227 " xmlns=\"" + transport_type + "\"" | |
228 ">" | |
229 + transport_main + | |
230 "</transport>"; | |
231 | |
232 return"<content" | |
233 " name=\"" + content_name + "\"" | |
234 " creator=\"initiator\"" | |
235 ">" | |
236 "<description" | |
237 " xmlns=\"" + content_type + "\"" | |
238 "/>" | |
239 + transport + | |
240 "</content>"; | |
241 } | |
242 | |
243 std::string JingleTransportContentXml(const std::string& content_name, | |
244 const std::string& transport_type, | |
245 const std::string& content) { | |
246 return "<content" | |
247 " name=\"" + content_name + "\"" | |
248 " creator=\"initiator\"" | |
249 ">" | |
250 "<transport" | |
251 " xmlns=\"" + transport_type + "\"" | |
252 ">" | |
253 + content + | |
254 "</transport>" | |
255 "</content>"; | |
256 } | |
257 | |
258 std::string GingleInitiateXml(const std::string& content_type) { | |
259 return GingleSessionXml( | |
260 "initiate", | |
261 GingleDescriptionXml(content_type)); | |
262 } | |
263 | |
264 std::string JingleInitiateXml(const std::string& content_name_a, | |
265 const std::string& content_type_a, | |
266 const std::string& content_name_b, | |
267 const std::string& content_type_b, | |
268 bool bundle = false) { | |
269 std::string content_xml; | |
270 if (content_name_b.empty()) { | |
271 content_xml = JingleEmptyContentXml( | |
272 content_name_a, content_type_a, kTransportType); | |
273 } else { | |
274 content_xml = JingleEmptyContentXml( | |
275 content_name_a, content_type_a, kTransportType) + | |
276 JingleEmptyContentXml( | |
277 content_name_b, content_type_b, kTransportType); | |
278 if (bundle) { | |
279 content_xml += JingleGroupInfoXml(content_name_a, content_name_b); | |
280 } | |
281 } | |
282 return JingleInitiateActionXml(content_xml); | |
283 } | |
284 | |
285 std::string GingleAcceptXml(const std::string& content_type) { | |
286 return GingleSessionXml( | |
287 "accept", | |
288 GingleDescriptionXml(content_type)); | |
289 } | |
290 | |
291 std::string JingleAcceptXml(const std::string& content_name_a, | |
292 const std::string& content_type_a, | |
293 const std::string& content_name_b, | |
294 const std::string& content_type_b, | |
295 bool bundle = false) { | |
296 std::string content_xml; | |
297 if (content_name_b.empty()) { | |
298 content_xml = JingleEmptyContentXml( | |
299 content_name_a, content_type_a, kTransportType); | |
300 } else { | |
301 content_xml = JingleEmptyContentXml( | |
302 content_name_a, content_type_a, kTransportType) + | |
303 JingleEmptyContentXml( | |
304 content_name_b, content_type_b, kTransportType); | |
305 } | |
306 if (bundle) { | |
307 content_xml += JingleGroupInfoXml(content_name_a, content_name_b); | |
308 } | |
309 | |
310 return JingleActionXml("session-accept", content_xml); | |
311 } | |
312 | |
313 std::string Gingle2CandidatesXml(const std::string& channel_name, | |
314 int port_index0, | |
315 int port_index1) { | |
316 return GingleSessionXml( | |
317 "candidates", | |
318 P2pCandidateXml(channel_name, port_index0) + | |
319 P2pCandidateXml(channel_name, port_index1)); | |
320 } | |
321 | |
322 std::string Gingle4CandidatesXml(const std::string& channel_name_a, | |
323 int port_index0, | |
324 int port_index1, | |
325 const std::string& channel_name_b, | |
326 int port_index2, | |
327 int port_index3) { | |
328 return GingleSessionXml( | |
329 "candidates", | |
330 P2pCandidateXml(channel_name_a, port_index0) + | |
331 P2pCandidateXml(channel_name_a, port_index1) + | |
332 P2pCandidateXml(channel_name_b, port_index2) + | |
333 P2pCandidateXml(channel_name_b, port_index3)); | |
334 } | |
335 | |
336 std::string Jingle2TransportInfoXml(const std::string& content_name, | |
337 const std::string& channel_name, | |
338 int port_index0, | |
339 int port_index1) { | |
340 return JingleActionXml( | |
341 "transport-info", | |
342 JingleTransportContentXml( | |
343 content_name, kTransportType, | |
344 P2pCandidateXml(channel_name, port_index0) + | |
345 P2pCandidateXml(channel_name, port_index1))); | |
346 } | |
347 | |
348 std::string Jingle4TransportInfoXml(const std::string& content_name, | |
349 const std::string& channel_name_a, | |
350 int port_index0, | |
351 int port_index1, | |
352 const std::string& channel_name_b, | |
353 int port_index2, | |
354 int port_index3) { | |
355 return JingleActionXml( | |
356 "transport-info", | |
357 JingleTransportContentXml( | |
358 content_name, kTransportType, | |
359 P2pCandidateXml(channel_name_a, port_index0) + | |
360 P2pCandidateXml(channel_name_a, port_index1) + | |
361 P2pCandidateXml(channel_name_b, port_index2) + | |
362 P2pCandidateXml(channel_name_b, port_index3))); | |
363 } | |
364 | |
365 std::string JingleDescriptionInfoXml(const std::string& content_name, | |
366 const std::string& content_type) { | |
367 return JingleActionXml( | |
368 "description-info", | |
369 JingleContentXml(content_name, content_type, "", "")); | |
370 } | |
371 | |
372 std::string GingleRejectXml(const std::string& reason) { | |
373 return GingleSessionXml( | |
374 "reject", | |
375 "<" + reason + "/>"); | |
376 } | |
377 | |
378 std::string JingleTerminateXml(const std::string& reason) { | |
379 return JingleActionXml( | |
380 "session-terminate", | |
381 "<reason><" + reason + "/></reason>"); | |
382 } | |
383 | |
384 std::string GingleTerminateXml(const std::string& reason) { | |
385 return GingleSessionXml( | |
386 "terminate", | |
387 "<" + reason + "/>"); | |
388 } | |
389 | |
390 std::string GingleRedirectXml(const std::string& intitiate, | |
391 const std::string& target) { | |
392 return intitiate + | |
393 "<error code=\"302\" type=\"modify\">" | |
394 "<redirect xmlns=\"http://www.google.com/session\">" | |
395 "xmpp:" + target + | |
396 "</redirect>" | |
397 "</error>"; | |
398 } | |
399 | |
400 std::string JingleRedirectXml(const std::string& intitiate, | |
401 const std::string& target) { | |
402 return intitiate + | |
403 "<error code=\"302\" type=\"modify\">" | |
404 "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">" | |
405 "xmpp:" + target + | |
406 "</redirect>" | |
407 "</error>"; | |
408 } | |
409 | |
410 std::string InitiateXml(SignalingProtocol protocol, | |
411 const std::string& gingle_content_type, | |
412 const std::string& content_name_a, | |
413 const std::string& content_type_a, | |
414 const std::string& content_name_b, | |
415 const std::string& content_type_b, | |
416 bool bundle = false) { | |
417 switch (protocol) { | |
418 case PROTOCOL_JINGLE: | |
419 return JingleInitiateXml(content_name_a, content_type_a, | |
420 content_name_b, content_type_b, | |
421 bundle); | |
422 case PROTOCOL_GINGLE: | |
423 return GingleInitiateXml(gingle_content_type); | |
424 case PROTOCOL_HYBRID: | |
425 return JingleInitiateXml(content_name_a, content_type_a, | |
426 content_name_b, content_type_b) + | |
427 GingleInitiateXml(gingle_content_type); | |
428 } | |
429 return ""; | |
430 } | |
431 | |
432 std::string InitiateXml(SignalingProtocol protocol, | |
433 const std::string& content_name, | |
434 const std::string& content_type) { | |
435 return InitiateXml(protocol, | |
436 content_type, | |
437 content_name, content_type, | |
438 "", ""); | |
439 } | |
440 | |
441 std::string AcceptXml(SignalingProtocol protocol, | |
442 const std::string& gingle_content_type, | |
443 const std::string& content_name_a, | |
444 const std::string& content_type_a, | |
445 const std::string& content_name_b, | |
446 const std::string& content_type_b, | |
447 bool bundle = false) { | |
448 switch (protocol) { | |
449 case PROTOCOL_JINGLE: | |
450 return JingleAcceptXml(content_name_a, content_type_a, | |
451 content_name_b, content_type_b, bundle); | |
452 case PROTOCOL_GINGLE: | |
453 return GingleAcceptXml(gingle_content_type); | |
454 case PROTOCOL_HYBRID: | |
455 return | |
456 JingleAcceptXml(content_name_a, content_type_a, | |
457 content_name_b, content_type_b) + | |
458 GingleAcceptXml(gingle_content_type); | |
459 } | |
460 return ""; | |
461 } | |
462 | |
463 | |
464 std::string AcceptXml(SignalingProtocol protocol, | |
465 const std::string& content_name, | |
466 const std::string& content_type, | |
467 bool bundle = false) { | |
468 return AcceptXml(protocol, | |
469 content_type, | |
470 content_name, content_type, | |
471 "", ""); | |
472 } | |
473 | |
474 std::string TransportInfo2Xml(SignalingProtocol protocol, | |
475 const std::string& content_name, | |
476 const std::string& channel_name, | |
477 int port_index0, | |
478 int port_index1) { | |
479 switch (protocol) { | |
480 case PROTOCOL_JINGLE: | |
481 return Jingle2TransportInfoXml( | |
482 content_name, | |
483 channel_name, port_index0, port_index1); | |
484 case PROTOCOL_GINGLE: | |
485 return Gingle2CandidatesXml( | |
486 channel_name, port_index0, port_index1); | |
487 case PROTOCOL_HYBRID: | |
488 return | |
489 Jingle2TransportInfoXml( | |
490 content_name, | |
491 channel_name, port_index0, port_index1) + | |
492 Gingle2CandidatesXml( | |
493 channel_name, port_index0, port_index1); | |
494 } | |
495 return ""; | |
496 } | |
497 | |
498 std::string TransportInfo4Xml(SignalingProtocol protocol, | |
499 const std::string& content_name, | |
500 const std::string& channel_name_a, | |
501 int port_index0, | |
502 int port_index1, | |
503 const std::string& channel_name_b, | |
504 int port_index2, | |
505 int port_index3) { | |
506 switch (protocol) { | |
507 case PROTOCOL_JINGLE: | |
508 return Jingle4TransportInfoXml( | |
509 content_name, | |
510 channel_name_a, port_index0, port_index1, | |
511 channel_name_b, port_index2, port_index3); | |
512 case PROTOCOL_GINGLE: | |
513 return Gingle4CandidatesXml( | |
514 channel_name_a, port_index0, port_index1, | |
515 channel_name_b, port_index2, port_index3); | |
516 case PROTOCOL_HYBRID: | |
517 return | |
518 Jingle4TransportInfoXml( | |
519 content_name, | |
520 channel_name_a, port_index0, port_index1, | |
521 channel_name_b, port_index2, port_index3) + | |
522 Gingle4CandidatesXml( | |
523 channel_name_a, port_index0, port_index1, | |
524 channel_name_b, port_index2, port_index3); | |
525 } | |
526 return ""; | |
527 } | |
528 | |
529 std::string RejectXml(SignalingProtocol protocol, | |
530 const std::string& reason) { | |
531 switch (protocol) { | |
532 case PROTOCOL_JINGLE: | |
533 return JingleTerminateXml(reason); | |
534 case PROTOCOL_GINGLE: | |
535 return GingleRejectXml(reason); | |
536 case PROTOCOL_HYBRID: | |
537 return JingleTerminateXml(reason) + | |
538 GingleRejectXml(reason); | |
539 } | |
540 return ""; | |
541 } | |
542 | |
543 std::string TerminateXml(SignalingProtocol protocol, | |
544 const std::string& reason) { | |
545 switch (protocol) { | |
546 case PROTOCOL_JINGLE: | |
547 return JingleTerminateXml(reason); | |
548 case PROTOCOL_GINGLE: | |
549 return GingleTerminateXml(reason); | |
550 case PROTOCOL_HYBRID: | |
551 return JingleTerminateXml(reason) + | |
552 GingleTerminateXml(reason); | |
553 } | |
554 return ""; | |
555 } | |
556 | |
557 std::string RedirectXml(SignalingProtocol protocol, | |
558 const std::string& initiate, | |
559 const std::string& target) { | |
560 switch (protocol) { | |
561 case PROTOCOL_JINGLE: | |
562 return JingleRedirectXml(initiate, target); | |
563 case PROTOCOL_GINGLE: | |
564 return GingleRedirectXml(initiate, target); | |
565 default: | |
566 break; | |
567 } | |
568 return ""; | |
569 } | |
570 | |
571 // TODO: Break out and join with fakeportallocator.h | |
572 class TestPortAllocatorSession : public cricket::PortAllocatorSession { | |
573 public: | |
574 TestPortAllocatorSession(const std::string& content_name, | |
575 int component, | |
576 const std::string& ice_ufrag, | |
577 const std::string& ice_pwd, | |
578 const int port_offset) | |
579 : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0), | |
580 port_offset_(port_offset), | |
581 ports_(kNumPorts), | |
582 address_("127.0.0.1", 0), | |
583 network_("network", "unittest", | |
584 rtc::IPAddress(INADDR_LOOPBACK), 8), | |
585 socket_factory_(rtc::Thread::Current()), | |
586 running_(false) { | |
587 network_.AddIP(address_.ipaddr()); | |
588 } | |
589 | |
590 ~TestPortAllocatorSession() { | |
591 for (size_t i = 0; i < ports_.size(); i++) | |
592 delete ports_[i]; | |
593 } | |
594 | |
595 virtual void StartGettingPorts() { | |
596 for (int i = 0; i < kNumPorts; i++) { | |
597 int index = port_offset_ + i; | |
598 ports_[i] = cricket::UDPPort::Create( | |
599 rtc::Thread::Current(), &socket_factory_, | |
600 &network_, address_.ipaddr(), GetPort(index), GetPort(index), | |
601 GetUsername(index), GetPassword(index), | |
602 std::string()); | |
603 AddPort(ports_[i]); | |
604 } | |
605 running_ = true; | |
606 } | |
607 | |
608 virtual void StopGettingPorts() { running_ = false; } | |
609 virtual bool IsGettingPorts() { return running_; } | |
610 | |
611 void AddPort(cricket::Port* port) { | |
612 port->set_component(component_); | |
613 port->set_generation(0); | |
614 port->SignalDestroyed.connect( | |
615 this, &TestPortAllocatorSession::OnPortDestroyed); | |
616 port->SignalPortComplete.connect( | |
617 this, &TestPortAllocatorSession::OnPortComplete); | |
618 port->PrepareAddress(); | |
619 SignalPortReady(this, port); | |
620 } | |
621 | |
622 void OnPortDestroyed(cricket::PortInterface* port) { | |
623 for (size_t i = 0; i < ports_.size(); i++) { | |
624 if (ports_[i] == port) | |
625 ports_[i] = NULL; | |
626 } | |
627 } | |
628 | |
629 void OnPortComplete(cricket::Port* port) { | |
630 SignalCandidatesReady(this, port->Candidates()); | |
631 } | |
632 | |
633 private: | |
634 int port_offset_; | |
635 std::vector<cricket::Port*> ports_; | |
636 rtc::SocketAddress address_; | |
637 rtc::Network network_; | |
638 rtc::BasicPacketSocketFactory socket_factory_; | |
639 bool running_; | |
640 }; | |
641 | |
642 class TestPortAllocator : public cricket::PortAllocator { | |
643 public: | |
644 TestPortAllocator() : port_offset_(0) {} | |
645 | |
646 virtual cricket::PortAllocatorSession* | |
647 CreateSessionInternal( | |
648 const std::string& content_name, | |
649 int component, | |
650 const std::string& ice_ufrag, | |
651 const std::string& ice_pwd) { | |
652 port_offset_ += 2; | |
653 return new TestPortAllocatorSession(content_name, component, | |
654 ice_ufrag, ice_pwd, port_offset_ - 2); | |
655 } | |
656 | |
657 int port_offset_; | |
658 }; | |
659 | |
660 class TestContentDescription : public cricket::ContentDescription { | |
661 public: | |
662 explicit TestContentDescription(const std::string& gingle_content_type, | |
663 const std::string& content_type) | |
664 : gingle_content_type(gingle_content_type), | |
665 content_type(content_type) { | |
666 } | |
667 virtual ContentDescription* Copy() const { | |
668 return new TestContentDescription(*this); | |
669 } | |
670 | |
671 std::string gingle_content_type; | |
672 std::string content_type; | |
673 }; | |
674 | |
675 cricket::SessionDescription* NewTestSessionDescription( | |
676 const std::string gingle_content_type, | |
677 const std::string& content_name_a, const std::string& content_type_a, | |
678 const std::string& content_name_b, const std::string& content_type_b) { | |
679 | |
680 cricket::SessionDescription* offer = new cricket::SessionDescription(); | |
681 offer->AddContent(content_name_a, content_type_a, | |
682 new TestContentDescription(gingle_content_type, | |
683 content_type_a)); | |
684 cricket::TransportDescription desc(cricket::NS_GINGLE_P2P, | |
685 std::string(), std::string()); | |
686 offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc)); | |
687 | |
688 if (content_name_a != content_name_b) { | |
689 offer->AddContent(content_name_b, content_type_b, | |
690 new TestContentDescription(gingle_content_type, | |
691 content_type_b)); | |
692 offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc)); | |
693 } | |
694 return offer; | |
695 } | |
696 | |
697 cricket::SessionDescription* NewTestSessionDescription( | |
698 const std::string& content_name, const std::string& content_type) { | |
699 | |
700 cricket::SessionDescription* offer = new cricket::SessionDescription(); | |
701 offer->AddContent(content_name, content_type, | |
702 new TestContentDescription(content_type, | |
703 content_type)); | |
704 offer->AddTransportInfo(cricket::TransportInfo | |
705 (content_name, cricket::TransportDescription( | |
706 cricket::NS_GINGLE_P2P, | |
707 std::string(), std::string()))); | |
708 return offer; | |
709 } | |
710 | |
711 struct TestSessionClient: public cricket::SessionClient, | |
712 public sigslot::has_slots<> { | |
713 public: | |
714 TestSessionClient() { | |
715 } | |
716 | |
717 ~TestSessionClient() { | |
718 } | |
719 | |
720 virtual bool ParseContent(SignalingProtocol protocol, | |
721 const buzz::XmlElement* elem, | |
722 cricket::ContentDescription** content, | |
723 cricket::ParseError* error) { | |
724 std::string content_type; | |
725 std::string gingle_content_type; | |
726 if (protocol == PROTOCOL_GINGLE) { | |
727 gingle_content_type = elem->Name().Namespace(); | |
728 } else { | |
729 content_type = elem->Name().Namespace(); | |
730 } | |
731 | |
732 *content = new TestContentDescription(gingle_content_type, content_type); | |
733 return true; | |
734 } | |
735 | |
736 virtual bool WriteContent(SignalingProtocol protocol, | |
737 const cricket::ContentDescription* untyped_content, | |
738 buzz::XmlElement** elem, | |
739 cricket::WriteError* error) { | |
740 const TestContentDescription* content = | |
741 static_cast<const TestContentDescription*>(untyped_content); | |
742 std::string content_type = (protocol == PROTOCOL_GINGLE ? | |
743 content->gingle_content_type : | |
744 content->content_type); | |
745 *elem = new buzz::XmlElement( | |
746 buzz::QName(content_type, "description"), true); | |
747 return true; | |
748 } | |
749 | |
750 void OnSessionCreate(cricket::Session* session, bool initiate) { | |
751 } | |
752 | |
753 void OnSessionDestroy(cricket::Session* session) { | |
754 } | |
755 }; | |
756 | |
757 struct ChannelHandler : sigslot::has_slots<> { | |
758 explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name) | |
759 : channel(p), last_readable(false), last_writable(false), data_count(0), | |
760 last_size(0), name(name) { | |
761 p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState); | |
762 p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState); | |
763 p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket); | |
764 } | |
765 | |
766 bool writable() const { | |
767 return last_writable && channel->writable(); | |
768 } | |
769 | |
770 bool readable() const { | |
771 return last_readable && channel->readable(); | |
772 } | |
773 | |
774 void OnReadableState(cricket::TransportChannel* p) { | |
775 EXPECT_EQ(channel, p); | |
776 last_readable = channel->readable(); | |
777 } | |
778 | |
779 void OnWritableState(cricket::TransportChannel* p) { | |
780 EXPECT_EQ(channel, p); | |
781 last_writable = channel->writable(); | |
782 } | |
783 | |
784 void OnReadPacket(cricket::TransportChannel* p, const char* buf, | |
785 size_t size, const rtc::PacketTime& time, int flags) { | |
786 if (memcmp(buf, name.c_str(), name.size()) != 0) | |
787 return; // drop packet if packet doesn't belong to this channel. This | |
788 // can happen when transport channels are muxed together. | |
789 buf += name.size(); // Remove channel name from the message. | |
790 size -= name.size(); // Decrement size by channel name string size. | |
791 EXPECT_EQ(channel, p); | |
792 EXPECT_LE(size, sizeof(last_data)); | |
793 data_count += 1; | |
794 last_size = size; | |
795 memcpy(last_data, buf, size); | |
796 } | |
797 | |
798 void Send(const char* data, size_t size) { | |
799 rtc::PacketOptions options; | |
800 std::string data_with_id(name); | |
801 data_with_id += data; | |
802 int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(), | |
803 options, 0); | |
804 EXPECT_EQ(static_cast<int>(data_with_id.size()), result); | |
805 } | |
806 | |
807 cricket::TransportChannel* channel; | |
808 bool last_readable, last_writable; | |
809 int data_count; | |
810 char last_data[4096]; | |
811 size_t last_size; | |
812 std::string name; | |
813 }; | |
814 | |
815 void PrintStanza(const std::string& message, | |
816 const buzz::XmlElement* stanza) { | |
817 printf("%s: %s\n", message.c_str(), stanza->Str().c_str()); | |
818 } | |
819 | |
820 class TestClient : public sigslot::has_slots<> { | |
821 public: | |
822 // TODO: Add channel_component_a/b as inputs to the ctor. | |
823 TestClient(cricket::PortAllocator* port_allocator, | |
824 int* next_message_id, | |
825 const std::string& local_name, | |
826 SignalingProtocol start_protocol, | |
827 const std::string& content_type, | |
828 const std::string& content_name_a, | |
829 const std::string& channel_name_a, | |
830 const std::string& content_name_b, | |
831 const std::string& channel_name_b) { | |
832 Construct(port_allocator, next_message_id, local_name, start_protocol, | |
833 content_type, content_name_a, channel_name_a, | |
834 content_name_b, channel_name_b); | |
835 } | |
836 | |
837 ~TestClient() { | |
838 if (session) { | |
839 session_manager->DestroySession(session); | |
840 EXPECT_EQ(1U, session_destroyed_count); | |
841 } | |
842 delete session_manager; | |
843 delete client; | |
844 for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin(); | |
845 it != sent_stanzas.end(); ++it) { | |
846 delete *it; | |
847 } | |
848 } | |
849 | |
850 void Construct(cricket::PortAllocator* pa, | |
851 int* message_id, | |
852 const std::string& lname, | |
853 SignalingProtocol protocol, | |
854 const std::string& cont_type, | |
855 const std::string& cont_name_a, | |
856 const std::string& chan_name_a, | |
857 const std::string& cont_name_b, | |
858 const std::string& chan_name_b) { | |
859 port_allocator_ = pa; | |
860 next_message_id = message_id; | |
861 local_name = lname; | |
862 start_protocol = protocol; | |
863 content_type = cont_type; | |
864 content_name_a = cont_name_a; | |
865 channel_name_a = chan_name_a; | |
866 content_name_b = cont_name_b; | |
867 channel_name_b = chan_name_b; | |
868 session_created_count = 0; | |
869 session_destroyed_count = 0; | |
870 session_remote_description_update_count = 0; | |
871 new_local_description = false; | |
872 new_remote_description = false; | |
873 last_content_action = cricket::CA_OFFER; | |
874 last_content_source = cricket::CS_LOCAL; | |
875 session = NULL; | |
876 last_session_state = cricket::BaseSession::STATE_INIT; | |
877 blow_up_on_error = true; | |
878 error_count = 0; | |
879 | |
880 session_manager = new cricket::SessionManager(port_allocator_); | |
881 session_manager->SignalSessionCreate.connect( | |
882 this, &TestClient::OnSessionCreate); | |
883 session_manager->SignalSessionDestroy.connect( | |
884 this, &TestClient::OnSessionDestroy); | |
885 session_manager->SignalOutgoingMessage.connect( | |
886 this, &TestClient::OnOutgoingMessage); | |
887 | |
888 client = new TestSessionClient(); | |
889 session_manager->AddClient(content_type, client); | |
890 EXPECT_EQ(client, session_manager->GetClient(content_type)); | |
891 } | |
892 | |
893 uint32 sent_stanza_count() const { | |
894 return static_cast<uint32>(sent_stanzas.size()); | |
895 } | |
896 | |
897 const buzz::XmlElement* stanza() const { | |
898 return last_expected_sent_stanza.get(); | |
899 } | |
900 | |
901 cricket::BaseSession::State session_state() const { | |
902 EXPECT_EQ(last_session_state, session->state()); | |
903 return session->state(); | |
904 } | |
905 | |
906 void SetSessionState(cricket::BaseSession::State state) { | |
907 session->SetState(state); | |
908 EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout); | |
909 } | |
910 | |
911 void CreateSession() { | |
912 session_manager->CreateSession(local_name, content_type); | |
913 } | |
914 | |
915 void DeliverStanza(const buzz::XmlElement* stanza) { | |
916 session_manager->OnIncomingMessage(stanza); | |
917 } | |
918 | |
919 void DeliverStanza(const std::string& str) { | |
920 buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str); | |
921 session_manager->OnIncomingMessage(stanza); | |
922 delete stanza; | |
923 } | |
924 | |
925 void DeliverAckToLastStanza() { | |
926 const buzz::XmlElement* orig_stanza = stanza(); | |
927 const buzz::XmlElement* response_stanza = | |
928 buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", "")); | |
929 session_manager->OnIncomingResponse(orig_stanza, response_stanza); | |
930 delete response_stanza; | |
931 } | |
932 | |
933 void ExpectSentStanza(const std::string& expected) { | |
934 EXPECT_TRUE(!sent_stanzas.empty()) << | |
935 "Found no stanza when expected " << expected; | |
936 | |
937 last_expected_sent_stanza.reset(sent_stanzas.front()); | |
938 sent_stanzas.pop_front(); | |
939 | |
940 std::string actual = last_expected_sent_stanza->Str(); | |
941 EXPECT_EQ(expected, actual); | |
942 } | |
943 | |
944 void SkipUnsentStanza() { | |
945 GetNextOutgoingMessageID(); | |
946 } | |
947 | |
948 bool HasTransport(const std::string& content_name) const { | |
949 ASSERT(session != NULL); | |
950 const cricket::Transport* transport = session->GetTransport(content_name); | |
951 return transport != NULL && (kTransportType == transport->type()); | |
952 } | |
953 | |
954 bool HasChannel(const std::string& content_name, | |
955 int component) const { | |
956 ASSERT(session != NULL); | |
957 const cricket::TransportChannel* channel = | |
958 session->GetChannel(content_name, component); | |
959 return channel != NULL && (component == channel->component()); | |
960 } | |
961 | |
962 cricket::TransportChannel* GetChannel(const std::string& content_name, | |
963 int component) const { | |
964 ASSERT(session != NULL); | |
965 return session->GetChannel(content_name, component); | |
966 } | |
967 | |
968 void OnSessionCreate(cricket::Session* created_session, bool initiate) { | |
969 session_created_count += 1; | |
970 | |
971 session = created_session; | |
972 session->set_current_protocol(start_protocol); | |
973 session->SignalState.connect(this, &TestClient::OnSessionState); | |
974 session->SignalError.connect(this, &TestClient::OnSessionError); | |
975 session->SignalRemoteDescriptionUpdate.connect( | |
976 this, &TestClient::OnSessionRemoteDescriptionUpdate); | |
977 session->SignalNewLocalDescription.connect( | |
978 this, &TestClient::OnNewLocalDescription); | |
979 session->SignalNewRemoteDescription.connect( | |
980 this, &TestClient::OnNewRemoteDescription); | |
981 | |
982 CreateChannels(); | |
983 } | |
984 | |
985 void OnSessionDestroy(cricket::Session *session) { | |
986 session_destroyed_count += 1; | |
987 } | |
988 | |
989 void OnSessionState(cricket::BaseSession* session, | |
990 cricket::BaseSession::State state) { | |
991 // EXPECT_EQ does not allow use of this, hence the tmp variable. | |
992 cricket::BaseSession* tmp = this->session; | |
993 EXPECT_EQ(tmp, session); | |
994 last_session_state = state; | |
995 } | |
996 | |
997 void OnSessionError(cricket::BaseSession* session, | |
998 cricket::BaseSession::Error error) { | |
999 // EXPECT_EQ does not allow use of this, hence the tmp variable. | |
1000 cricket::BaseSession* tmp = this->session; | |
1001 EXPECT_EQ(tmp, session); | |
1002 if (blow_up_on_error) { | |
1003 EXPECT_TRUE(false); | |
1004 } else { | |
1005 error_count++; | |
1006 } | |
1007 } | |
1008 | |
1009 void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session, | |
1010 const cricket::ContentInfos& contents) { | |
1011 session_remote_description_update_count++; | |
1012 } | |
1013 | |
1014 void OnNewLocalDescription(cricket::BaseSession* session, | |
1015 cricket::ContentAction action) { | |
1016 new_local_description = true; | |
1017 last_content_action = action; | |
1018 last_content_source = cricket::CS_LOCAL; | |
1019 } | |
1020 | |
1021 void OnNewRemoteDescription(cricket::BaseSession* session, | |
1022 cricket::ContentAction action) { | |
1023 new_remote_description = true; | |
1024 last_content_action = action; | |
1025 last_content_source = cricket::CS_REMOTE; | |
1026 } | |
1027 | |
1028 void PrepareCandidates() { | |
1029 session_manager->OnSignalingReady(); | |
1030 } | |
1031 | |
1032 void OnOutgoingMessage(cricket::SessionManager* manager, | |
1033 const buzz::XmlElement* stanza) { | |
1034 buzz::XmlElement* elem = new buzz::XmlElement(*stanza); | |
1035 EXPECT_TRUE(elem->Name() == buzz::QN_IQ); | |
1036 EXPECT_TRUE(elem->HasAttr(buzz::QN_TO)); | |
1037 EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM)); | |
1038 EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE)); | |
1039 EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") || | |
1040 (elem->Attr(buzz::QN_TYPE) == "result") || | |
1041 (elem->Attr(buzz::QN_TYPE) == "error")); | |
1042 | |
1043 elem->SetAttr(buzz::QN_FROM, local_name); | |
1044 if (elem->Attr(buzz::QN_TYPE) == "set") { | |
1045 EXPECT_FALSE(elem->HasAttr(buzz::QN_ID)); | |
1046 elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID()); | |
1047 } | |
1048 | |
1049 // Uncommenting this is useful for debugging. | |
1050 // PrintStanza("OutgoingMessage", elem); | |
1051 sent_stanzas.push_back(elem); | |
1052 } | |
1053 | |
1054 std::string GetNextOutgoingMessageID() { | |
1055 int message_id = (*next_message_id)++; | |
1056 std::ostringstream ost; | |
1057 ost << message_id; | |
1058 return ost.str(); | |
1059 } | |
1060 | |
1061 void CreateChannels() { | |
1062 ASSERT(session != NULL); | |
1063 // We either have a single content with multiple components (RTP/RTCP), or | |
1064 // multiple contents with single components, but not both. | |
1065 int component_a = 1; | |
1066 int component_b = (content_name_a == content_name_b) ? 2 : 1; | |
1067 chan_a.reset(new ChannelHandler( | |
1068 session->CreateChannel(content_name_a, channel_name_a, component_a), | |
1069 channel_name_a)); | |
1070 chan_b.reset(new ChannelHandler( | |
1071 session->CreateChannel(content_name_b, channel_name_b, component_b), | |
1072 channel_name_b)); | |
1073 } | |
1074 | |
1075 int* next_message_id; | |
1076 std::string local_name; | |
1077 SignalingProtocol start_protocol; | |
1078 std::string content_type; | |
1079 std::string content_name_a; | |
1080 std::string channel_name_a; | |
1081 std::string content_name_b; | |
1082 std::string channel_name_b; | |
1083 | |
1084 uint32 session_created_count; | |
1085 uint32 session_destroyed_count; | |
1086 uint32 session_remote_description_update_count; | |
1087 bool new_local_description; | |
1088 bool new_remote_description; | |
1089 cricket::ContentAction last_content_action; | |
1090 cricket::ContentSource last_content_source; | |
1091 std::deque<buzz::XmlElement*> sent_stanzas; | |
1092 rtc::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza; | |
1093 | |
1094 cricket::SessionManager* session_manager; | |
1095 TestSessionClient* client; | |
1096 cricket::PortAllocator* port_allocator_; | |
1097 cricket::Session* session; | |
1098 cricket::BaseSession::State last_session_state; | |
1099 rtc::scoped_ptr<ChannelHandler> chan_a; | |
1100 rtc::scoped_ptr<ChannelHandler> chan_b; | |
1101 bool blow_up_on_error; | |
1102 int error_count; | |
1103 }; | |
1104 | |
1105 class SessionTest : public testing::Test { | |
1106 protected: | |
1107 virtual void SetUp() { | |
1108 // Seed needed for each test to satisfy expectations. | |
1109 rtc::SetRandomTestMode(true); | |
1110 } | |
1111 | |
1112 virtual void TearDown() { | |
1113 rtc::SetRandomTestMode(false); | |
1114 } | |
1115 | |
1116 // Tests sending data between two clients, over two channels. | |
1117 void TestSendRecv(ChannelHandler* chan1a, | |
1118 ChannelHandler* chan1b, | |
1119 ChannelHandler* chan2a, | |
1120 ChannelHandler* chan2b) { | |
1121 const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam"; | |
1122 const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps"; | |
1123 const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce..."; | |
1124 const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL"; | |
1125 | |
1126 for (int i = 0; i < 20; i++) { | |
1127 chan1a->Send(dat1a, strlen(dat1a)); | |
1128 chan1b->Send(dat1b, strlen(dat1b)); | |
1129 chan2a->Send(dat2a, strlen(dat2a)); | |
1130 chan2b->Send(dat2b, strlen(dat2b)); | |
1131 | |
1132 EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout); | |
1133 EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout); | |
1134 EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout); | |
1135 EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout); | |
1136 | |
1137 EXPECT_EQ(strlen(dat2a), chan1a->last_size); | |
1138 EXPECT_EQ(strlen(dat2b), chan1b->last_size); | |
1139 EXPECT_EQ(strlen(dat1a), chan2a->last_size); | |
1140 EXPECT_EQ(strlen(dat1b), chan2b->last_size); | |
1141 | |
1142 EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a))); | |
1143 EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b))); | |
1144 EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a))); | |
1145 EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b))); | |
1146 } | |
1147 } | |
1148 | |
1149 // Test an initiate from one client to another, each with | |
1150 // independent initial protocols. Checks for the correct initiates, | |
1151 // candidates, and accept messages, and tests that working network | |
1152 // channels are established. | |
1153 void TestSession(SignalingProtocol initiator_protocol, | |
1154 SignalingProtocol responder_protocol, | |
1155 SignalingProtocol resulting_protocol, | |
1156 const std::string& gingle_content_type, | |
1157 const std::string& content_type, | |
1158 const std::string& content_name_a, | |
1159 const std::string& channel_name_a, | |
1160 const std::string& content_name_b, | |
1161 const std::string& channel_name_b, | |
1162 const std::string& initiate_xml, | |
1163 const std::string& transport_info_a_xml, | |
1164 const std::string& transport_info_b_xml, | |
1165 const std::string& transport_info_reply_a_xml, | |
1166 const std::string& transport_info_reply_b_xml, | |
1167 const std::string& accept_xml, | |
1168 bool bundle = false) { | |
1169 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
1170 new TestPortAllocator()); | |
1171 int next_message_id = 0; | |
1172 | |
1173 rtc::scoped_ptr<TestClient> initiator( | |
1174 new TestClient(allocator.get(), &next_message_id, | |
1175 kInitiator, initiator_protocol, | |
1176 content_type, | |
1177 content_name_a, channel_name_a, | |
1178 content_name_b, channel_name_b)); | |
1179 rtc::scoped_ptr<TestClient> responder( | |
1180 new TestClient(allocator.get(), &next_message_id, | |
1181 kResponder, responder_protocol, | |
1182 content_type, | |
1183 content_name_a, channel_name_a, | |
1184 content_name_b, channel_name_b)); | |
1185 | |
1186 // Create Session and check channels and state. | |
1187 initiator->CreateSession(); | |
1188 EXPECT_EQ(1U, initiator->session_created_count); | |
1189 EXPECT_EQ(kSessionId, initiator->session->id()); | |
1190 EXPECT_EQ(initiator->session->local_name(), kInitiator); | |
1191 EXPECT_EQ(cricket::BaseSession::STATE_INIT, | |
1192 initiator->session_state()); | |
1193 | |
1194 // See comment in CreateChannels about how we choose component IDs. | |
1195 int component_a = 1; | |
1196 int component_b = (content_name_a == content_name_b) ? 2 : 1; | |
1197 EXPECT_TRUE(initiator->HasTransport(content_name_a)); | |
1198 EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a)); | |
1199 EXPECT_TRUE(initiator->HasTransport(content_name_b)); | |
1200 EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b)); | |
1201 | |
1202 // Initiate and expect initiate message sent. | |
1203 cricket::SessionDescription* offer = NewTestSessionDescription( | |
1204 gingle_content_type, | |
1205 content_name_a, content_type, | |
1206 content_name_b, content_type); | |
1207 if (bundle) { | |
1208 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); | |
1209 group.AddContentName(content_name_a); | |
1210 group.AddContentName(content_name_b); | |
1211 EXPECT_TRUE(group.HasContentName(content_name_a)); | |
1212 EXPECT_TRUE(group.HasContentName(content_name_b)); | |
1213 offer->AddGroup(group); | |
1214 } | |
1215 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); | |
1216 EXPECT_EQ(initiator->session->remote_name(), kResponder); | |
1217 EXPECT_EQ(initiator->session->local_description(), offer); | |
1218 | |
1219 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1220 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
1221 initiator->session_state()); | |
1222 | |
1223 initiator->ExpectSentStanza( | |
1224 IqSet("0", kInitiator, kResponder, initiate_xml)); | |
1225 | |
1226 // Deliver the initiate. Expect ack and session created with | |
1227 // transports. | |
1228 responder->DeliverStanza(initiator->stanza()); | |
1229 responder->ExpectSentStanza( | |
1230 IqAck("0", kResponder, kInitiator)); | |
1231 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1232 | |
1233 EXPECT_EQ(1U, responder->session_created_count); | |
1234 EXPECT_EQ(kSessionId, responder->session->id()); | |
1235 EXPECT_EQ(responder->session->local_name(), kResponder); | |
1236 EXPECT_EQ(responder->session->remote_name(), kInitiator); | |
1237 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
1238 responder->session_state()); | |
1239 | |
1240 EXPECT_TRUE(responder->HasTransport(content_name_a)); | |
1241 EXPECT_TRUE(responder->HasChannel(content_name_a, component_a)); | |
1242 EXPECT_TRUE(responder->HasTransport(content_name_b)); | |
1243 EXPECT_TRUE(responder->HasChannel(content_name_b, component_b)); | |
1244 | |
1245 // Expect transport-info message from initiator. | |
1246 // But don't send candidates until initiate ack is received. | |
1247 initiator->PrepareCandidates(); | |
1248 WAIT(initiator->sent_stanza_count() > 0, 100); | |
1249 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1250 initiator->DeliverAckToLastStanza(); | |
1251 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1252 initiator->ExpectSentStanza( | |
1253 IqSet("1", kInitiator, kResponder, transport_info_a_xml)); | |
1254 | |
1255 // Deliver transport-info and expect ack. | |
1256 responder->DeliverStanza(initiator->stanza()); | |
1257 responder->ExpectSentStanza( | |
1258 IqAck("1", kResponder, kInitiator)); | |
1259 | |
1260 if (!transport_info_b_xml.empty()) { | |
1261 // Expect second transport-info message from initiator. | |
1262 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1263 initiator->ExpectSentStanza( | |
1264 IqSet("2", kInitiator, kResponder, transport_info_b_xml)); | |
1265 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1266 | |
1267 // Deliver second transport-info message and expect ack. | |
1268 responder->DeliverStanza(initiator->stanza()); | |
1269 responder->ExpectSentStanza( | |
1270 IqAck("2", kResponder, kInitiator)); | |
1271 } else { | |
1272 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1273 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1274 initiator->SkipUnsentStanza(); | |
1275 } | |
1276 | |
1277 // Expect reply transport-info message from responder. | |
1278 responder->PrepareCandidates(); | |
1279 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); | |
1280 responder->ExpectSentStanza( | |
1281 IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml)); | |
1282 | |
1283 // Deliver reply transport-info and expect ack. | |
1284 initiator->DeliverStanza(responder->stanza()); | |
1285 initiator->ExpectSentStanza( | |
1286 IqAck("3", kInitiator, kResponder)); | |
1287 | |
1288 if (!transport_info_reply_b_xml.empty()) { | |
1289 // Expect second reply transport-info message from responder. | |
1290 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); | |
1291 responder->ExpectSentStanza( | |
1292 IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml)); | |
1293 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1294 | |
1295 // Deliver second reply transport-info message and expect ack. | |
1296 initiator->DeliverStanza(responder->stanza()); | |
1297 initiator->ExpectSentStanza( | |
1298 IqAck("4", kInitiator, kResponder)); | |
1299 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1300 } else { | |
1301 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1302 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1303 responder->SkipUnsentStanza(); | |
1304 } | |
1305 | |
1306 // The channels should be able to become writable at this point. This | |
1307 // requires pinging, so it may take a little while. | |
1308 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && | |
1309 initiator->chan_a->readable(), kEventTimeout); | |
1310 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && | |
1311 initiator->chan_b->readable(), kEventTimeout); | |
1312 EXPECT_TRUE_WAIT(responder->chan_a->writable() && | |
1313 responder->chan_a->readable(), kEventTimeout); | |
1314 EXPECT_TRUE_WAIT(responder->chan_b->writable() && | |
1315 responder->chan_b->readable(), kEventTimeout); | |
1316 | |
1317 // Accept the session and expect accept stanza. | |
1318 cricket::SessionDescription* answer = NewTestSessionDescription( | |
1319 gingle_content_type, | |
1320 content_name_a, content_type, | |
1321 content_name_b, content_type); | |
1322 if (bundle) { | |
1323 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); | |
1324 group.AddContentName(content_name_a); | |
1325 group.AddContentName(content_name_b); | |
1326 EXPECT_TRUE(group.HasContentName(content_name_a)); | |
1327 EXPECT_TRUE(group.HasContentName(content_name_b)); | |
1328 answer->AddGroup(group); | |
1329 } | |
1330 EXPECT_TRUE(responder->session->Accept(answer)); | |
1331 EXPECT_EQ(responder->session->local_description(), answer); | |
1332 | |
1333 responder->ExpectSentStanza( | |
1334 IqSet("5", kResponder, kInitiator, accept_xml)); | |
1335 | |
1336 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1337 | |
1338 // Deliver the accept message and expect an ack. | |
1339 initiator->DeliverStanza(responder->stanza()); | |
1340 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1341 initiator->ExpectSentStanza( | |
1342 IqAck("5", kInitiator, kResponder)); | |
1343 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1344 | |
1345 // Both sessions should be in progress and have functioning | |
1346 // channels. | |
1347 EXPECT_EQ(resulting_protocol, initiator->session->current_protocol()); | |
1348 EXPECT_EQ(resulting_protocol, responder->session->current_protocol()); | |
1349 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1350 initiator->session_state(), kEventTimeout); | |
1351 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1352 responder->session_state(), kEventTimeout); | |
1353 if (bundle) { | |
1354 cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel; | |
1355 cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel; | |
1356 | |
1357 // Since we know these are TransportChannelProxy, type cast it. | |
1358 cricket::TransportChannelProxy* initiator_proxy_chan_a = | |
1359 static_cast<cricket::TransportChannelProxy*>(initiator_chan_a); | |
1360 cricket::TransportChannelProxy* initiator_proxy_chan_b = | |
1361 static_cast<cricket::TransportChannelProxy*>(initiator_chan_b); | |
1362 EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL); | |
1363 EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL); | |
1364 EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl()); | |
1365 | |
1366 cricket::TransportChannel* responder_chan_a = responder->chan_a->channel; | |
1367 cricket::TransportChannel* responder_chan_b = responder->chan_b->channel; | |
1368 | |
1369 // Since we know these are TransportChannelProxy, type cast it. | |
1370 cricket::TransportChannelProxy* responder_proxy_chan_a = | |
1371 static_cast<cricket::TransportChannelProxy*>(responder_chan_a); | |
1372 cricket::TransportChannelProxy* responder_proxy_chan_b = | |
1373 static_cast<cricket::TransportChannelProxy*>(responder_chan_b); | |
1374 EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL); | |
1375 EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL); | |
1376 EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl()); | |
1377 } | |
1378 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), | |
1379 responder->chan_a.get(), responder->chan_b.get()); | |
1380 | |
1381 if (resulting_protocol == PROTOCOL_JINGLE) { | |
1382 // Deliver a description-info message to the initiator and check if the | |
1383 // content description changes. | |
1384 EXPECT_EQ(0U, initiator->session_remote_description_update_count); | |
1385 | |
1386 const cricket::SessionDescription* old_session_desc = | |
1387 initiator->session->remote_description(); | |
1388 const cricket::ContentInfo* old_content_a = | |
1389 old_session_desc->GetContentByName(content_name_a); | |
1390 const cricket::ContentDescription* old_content_desc_a = | |
1391 old_content_a->description; | |
1392 const cricket::ContentInfo* old_content_b = | |
1393 old_session_desc->GetContentByName(content_name_b); | |
1394 const cricket::ContentDescription* old_content_desc_b = | |
1395 old_content_b->description; | |
1396 EXPECT_TRUE(old_content_desc_a != NULL); | |
1397 EXPECT_TRUE(old_content_desc_b != NULL); | |
1398 | |
1399 LOG(LS_INFO) << "A " << old_content_a->name; | |
1400 LOG(LS_INFO) << "B " << old_content_b->name; | |
1401 | |
1402 std::string description_info_xml = | |
1403 JingleDescriptionInfoXml(content_name_a, content_type); | |
1404 initiator->DeliverStanza( | |
1405 IqSet("6", kResponder, kInitiator, description_info_xml)); | |
1406 responder->SkipUnsentStanza(); | |
1407 EXPECT_EQ(1U, initiator->session_remote_description_update_count); | |
1408 | |
1409 const cricket::SessionDescription* new_session_desc = | |
1410 initiator->session->remote_description(); | |
1411 const cricket::ContentInfo* new_content_a = | |
1412 new_session_desc->GetContentByName(content_name_a); | |
1413 const cricket::ContentDescription* new_content_desc_a = | |
1414 new_content_a->description; | |
1415 const cricket::ContentInfo* new_content_b = | |
1416 new_session_desc->GetContentByName(content_name_b); | |
1417 const cricket::ContentDescription* new_content_desc_b = | |
1418 new_content_b->description; | |
1419 EXPECT_TRUE(new_content_desc_a != NULL); | |
1420 EXPECT_TRUE(new_content_desc_b != NULL); | |
1421 | |
1422 // TODO: We used to replace contents from an update, but | |
1423 // that no longer works with partial updates. We need to figure out | |
1424 // a way to merge patial updates into contents. For now, users of | |
1425 // Session should listen to SignalRemoteDescriptionUpdate and handle | |
1426 // updates. They should not expect remote_description to be the | |
1427 // latest value. | |
1428 // See session.cc OnDescriptionInfoMessage. | |
1429 | |
1430 // EXPECT_NE(old_content_desc_a, new_content_desc_a); | |
1431 | |
1432 // if (content_name_a != content_name_b) { | |
1433 // // If content_name_a != content_name_b, then b's content description | |
1434 // // should not have changed since the description-info message only | |
1435 // // contained an update for content_name_a. | |
1436 // EXPECT_EQ(old_content_desc_b, new_content_desc_b); | |
1437 // } | |
1438 | |
1439 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1440 initiator->ExpectSentStanza( | |
1441 IqAck("6", kInitiator, kResponder)); | |
1442 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1443 } else { | |
1444 responder->SkipUnsentStanza(); | |
1445 } | |
1446 | |
1447 initiator->session->Terminate(); | |
1448 initiator->ExpectSentStanza( | |
1449 IqSet("7", kInitiator, kResponder, | |
1450 TerminateXml(resulting_protocol, | |
1451 cricket::STR_TERMINATE_SUCCESS))); | |
1452 | |
1453 responder->DeliverStanza(initiator->stanza()); | |
1454 responder->ExpectSentStanza( | |
1455 IqAck("7", kResponder, kInitiator)); | |
1456 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, | |
1457 initiator->session_state()); | |
1458 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, | |
1459 responder->session_state()); | |
1460 } | |
1461 | |
1462 // Test an initiate with other content, called "main". | |
1463 void TestOtherContent(SignalingProtocol initiator_protocol, | |
1464 SignalingProtocol responder_protocol, | |
1465 SignalingProtocol resulting_protocol) { | |
1466 std::string content_name = "main"; | |
1467 std::string content_type = "http://oink.splat/session"; | |
1468 std::string content_name_a = content_name; | |
1469 std::string channel_name_a = "rtp"; | |
1470 std::string content_name_b = content_name; | |
1471 std::string channel_name_b = "rtcp"; | |
1472 std::string initiate_xml = InitiateXml( | |
1473 initiator_protocol, | |
1474 content_name_a, content_type); | |
1475 std::string transport_info_a_xml = TransportInfo4Xml( | |
1476 initiator_protocol, content_name, | |
1477 channel_name_a, 0, 1, | |
1478 channel_name_b, 2, 3); | |
1479 std::string transport_info_b_xml = ""; | |
1480 std::string transport_info_reply_a_xml = TransportInfo4Xml( | |
1481 resulting_protocol, content_name, | |
1482 channel_name_a, 4, 5, | |
1483 channel_name_b, 6, 7); | |
1484 std::string transport_info_reply_b_xml = ""; | |
1485 std::string accept_xml = AcceptXml( | |
1486 resulting_protocol, | |
1487 content_name_a, content_type); | |
1488 | |
1489 | |
1490 TestSession(initiator_protocol, responder_protocol, resulting_protocol, | |
1491 content_type, | |
1492 content_type, | |
1493 content_name_a, channel_name_a, | |
1494 content_name_b, channel_name_b, | |
1495 initiate_xml, | |
1496 transport_info_a_xml, transport_info_b_xml, | |
1497 transport_info_reply_a_xml, transport_info_reply_b_xml, | |
1498 accept_xml); | |
1499 } | |
1500 | |
1501 // Test an initiate with audio content. | |
1502 void TestAudioContent(SignalingProtocol initiator_protocol, | |
1503 SignalingProtocol responder_protocol, | |
1504 SignalingProtocol resulting_protocol) { | |
1505 std::string gingle_content_type = cricket::NS_GINGLE_AUDIO; | |
1506 std::string content_name = cricket::CN_AUDIO; | |
1507 std::string content_type = cricket::NS_JINGLE_RTP; | |
1508 std::string channel_name_a = "rtp"; | |
1509 std::string channel_name_b = "rtcp"; | |
1510 std::string initiate_xml = InitiateXml( | |
1511 initiator_protocol, | |
1512 gingle_content_type, | |
1513 content_name, content_type, | |
1514 "", ""); | |
1515 std::string transport_info_a_xml = TransportInfo4Xml( | |
1516 initiator_protocol, content_name, | |
1517 channel_name_a, 0, 1, | |
1518 channel_name_b, 2, 3); | |
1519 std::string transport_info_b_xml = ""; | |
1520 std::string transport_info_reply_a_xml = TransportInfo4Xml( | |
1521 resulting_protocol, content_name, | |
1522 channel_name_a, 4, 5, | |
1523 channel_name_b, 6, 7); | |
1524 std::string transport_info_reply_b_xml = ""; | |
1525 std::string accept_xml = AcceptXml( | |
1526 resulting_protocol, | |
1527 gingle_content_type, | |
1528 content_name, content_type, | |
1529 "", ""); | |
1530 | |
1531 | |
1532 TestSession(initiator_protocol, responder_protocol, resulting_protocol, | |
1533 gingle_content_type, | |
1534 content_type, | |
1535 content_name, channel_name_a, | |
1536 content_name, channel_name_b, | |
1537 initiate_xml, | |
1538 transport_info_a_xml, transport_info_b_xml, | |
1539 transport_info_reply_a_xml, transport_info_reply_b_xml, | |
1540 accept_xml); | |
1541 } | |
1542 | |
1543 // Since media content is "split" into two contents (audio and | |
1544 // video), we need to treat it special. | |
1545 void TestVideoContents(SignalingProtocol initiator_protocol, | |
1546 SignalingProtocol responder_protocol, | |
1547 SignalingProtocol resulting_protocol) { | |
1548 std::string content_type = cricket::NS_JINGLE_RTP; | |
1549 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; | |
1550 std::string content_name_a = cricket::CN_AUDIO; | |
1551 std::string channel_name_a = "rtp"; | |
1552 std::string content_name_b = cricket::CN_VIDEO; | |
1553 std::string channel_name_b = "video_rtp"; | |
1554 | |
1555 std::string initiate_xml = InitiateXml( | |
1556 initiator_protocol, | |
1557 gingle_content_type, | |
1558 content_name_a, content_type, | |
1559 content_name_b, content_type); | |
1560 std::string transport_info_a_xml = TransportInfo2Xml( | |
1561 initiator_protocol, content_name_a, | |
1562 channel_name_a, 0, 1); | |
1563 std::string transport_info_b_xml = TransportInfo2Xml( | |
1564 initiator_protocol, content_name_b, | |
1565 channel_name_b, 2, 3); | |
1566 std::string transport_info_reply_a_xml = TransportInfo2Xml( | |
1567 resulting_protocol, content_name_a, | |
1568 channel_name_a, 4, 5); | |
1569 std::string transport_info_reply_b_xml = TransportInfo2Xml( | |
1570 resulting_protocol, content_name_b, | |
1571 channel_name_b, 6, 7); | |
1572 std::string accept_xml = AcceptXml( | |
1573 resulting_protocol, | |
1574 gingle_content_type, | |
1575 content_name_a, content_type, | |
1576 content_name_b, content_type); | |
1577 | |
1578 TestSession(initiator_protocol, responder_protocol, resulting_protocol, | |
1579 gingle_content_type, | |
1580 content_type, | |
1581 content_name_a, channel_name_a, | |
1582 content_name_b, channel_name_b, | |
1583 initiate_xml, | |
1584 transport_info_a_xml, transport_info_b_xml, | |
1585 transport_info_reply_a_xml, transport_info_reply_b_xml, | |
1586 accept_xml); | |
1587 } | |
1588 | |
1589 void TestBadRedirect(SignalingProtocol protocol) { | |
1590 std::string content_name = "main"; | |
1591 std::string content_type = "http://oink.splat/session"; | |
1592 std::string channel_name_a = "chana"; | |
1593 std::string channel_name_b = "chanb"; | |
1594 std::string initiate_xml = InitiateXml( | |
1595 protocol, content_name, content_type); | |
1596 std::string transport_info_xml = TransportInfo4Xml( | |
1597 protocol, content_name, | |
1598 channel_name_a, 0, 1, | |
1599 channel_name_b, 2, 3); | |
1600 std::string transport_info_reply_xml = TransportInfo4Xml( | |
1601 protocol, content_name, | |
1602 channel_name_a, 4, 5, | |
1603 channel_name_b, 6, 7); | |
1604 std::string accept_xml = AcceptXml( | |
1605 protocol, content_name, content_type); | |
1606 std::string responder_full = kResponder + "/full"; | |
1607 | |
1608 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
1609 new TestPortAllocator()); | |
1610 int next_message_id = 0; | |
1611 | |
1612 rtc::scoped_ptr<TestClient> initiator( | |
1613 new TestClient(allocator.get(), &next_message_id, | |
1614 kInitiator, protocol, | |
1615 content_type, | |
1616 content_name, channel_name_a, | |
1617 content_name, channel_name_b)); | |
1618 | |
1619 rtc::scoped_ptr<TestClient> responder( | |
1620 new TestClient(allocator.get(), &next_message_id, | |
1621 responder_full, protocol, | |
1622 content_type, | |
1623 content_name, channel_name_a, | |
1624 content_name, channel_name_b)); | |
1625 | |
1626 // Create Session and check channels and state. | |
1627 initiator->CreateSession(); | |
1628 EXPECT_EQ(1U, initiator->session_created_count); | |
1629 EXPECT_EQ(kSessionId, initiator->session->id()); | |
1630 EXPECT_EQ(initiator->session->local_name(), kInitiator); | |
1631 EXPECT_EQ(cricket::BaseSession::STATE_INIT, | |
1632 initiator->session_state()); | |
1633 | |
1634 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); | |
1635 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); | |
1636 | |
1637 // Initiate and expect initiate message sent. | |
1638 cricket::SessionDescription* offer = NewTestSessionDescription( | |
1639 content_name, content_type); | |
1640 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); | |
1641 EXPECT_EQ(initiator->session->remote_name(), kResponder); | |
1642 EXPECT_EQ(initiator->session->local_description(), offer); | |
1643 | |
1644 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1645 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
1646 initiator->session_state()); | |
1647 initiator->ExpectSentStanza( | |
1648 IqSet("0", kInitiator, kResponder, initiate_xml)); | |
1649 | |
1650 // Expect transport-info message from initiator. | |
1651 initiator->DeliverAckToLastStanza(); | |
1652 initiator->PrepareCandidates(); | |
1653 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1654 initiator->ExpectSentStanza( | |
1655 IqSet("1", kInitiator, kResponder, transport_info_xml)); | |
1656 | |
1657 // Send an unauthorized redirect to the initiator and expect it be ignored. | |
1658 initiator->blow_up_on_error = false; | |
1659 const buzz::XmlElement* initiate_stanza = initiator->stanza(); | |
1660 rtc::scoped_ptr<buzz::XmlElement> redirect_stanza( | |
1661 buzz::XmlElement::ForStr( | |
1662 IqError("ER", kResponder, kInitiator, | |
1663 RedirectXml(protocol, initiate_xml, "not@allowed.com")))); | |
1664 initiator->session_manager->OnFailedSend( | |
1665 initiate_stanza, redirect_stanza.get()); | |
1666 EXPECT_EQ(initiator->session->remote_name(), kResponder); | |
1667 initiator->blow_up_on_error = true; | |
1668 EXPECT_EQ(initiator->error_count, 1); | |
1669 } | |
1670 | |
1671 void TestGoodRedirect(SignalingProtocol protocol) { | |
1672 std::string content_name = "main"; | |
1673 std::string content_type = "http://oink.splat/session"; | |
1674 std::string channel_name_a = "chana"; | |
1675 std::string channel_name_b = "chanb"; | |
1676 std::string initiate_xml = InitiateXml( | |
1677 protocol, content_name, content_type); | |
1678 std::string transport_info_xml = TransportInfo4Xml( | |
1679 protocol, content_name, | |
1680 channel_name_a, 0, 1, | |
1681 channel_name_b, 2, 3); | |
1682 std::string transport_info_reply_xml = TransportInfo4Xml( | |
1683 protocol, content_name, | |
1684 channel_name_a, 4, 5, | |
1685 channel_name_b, 6, 7); | |
1686 std::string accept_xml = AcceptXml( | |
1687 protocol, content_name, content_type); | |
1688 std::string responder_full = kResponder + "/full"; | |
1689 | |
1690 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
1691 new TestPortAllocator()); | |
1692 int next_message_id = 0; | |
1693 | |
1694 rtc::scoped_ptr<TestClient> initiator( | |
1695 new TestClient(allocator.get(), &next_message_id, | |
1696 kInitiator, protocol, | |
1697 content_type, | |
1698 content_name, channel_name_a, | |
1699 content_name, channel_name_b)); | |
1700 | |
1701 rtc::scoped_ptr<TestClient> responder( | |
1702 new TestClient(allocator.get(), &next_message_id, | |
1703 responder_full, protocol, | |
1704 content_type, | |
1705 content_name, channel_name_a, | |
1706 content_name, channel_name_b)); | |
1707 | |
1708 // Create Session and check channels and state. | |
1709 initiator->CreateSession(); | |
1710 EXPECT_EQ(1U, initiator->session_created_count); | |
1711 EXPECT_EQ(kSessionId, initiator->session->id()); | |
1712 EXPECT_EQ(initiator->session->local_name(), kInitiator); | |
1713 EXPECT_EQ(cricket::BaseSession::STATE_INIT, | |
1714 initiator->session_state()); | |
1715 | |
1716 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); | |
1717 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); | |
1718 | |
1719 // Initiate and expect initiate message sent. | |
1720 cricket::SessionDescription* offer = NewTestSessionDescription( | |
1721 content_name, content_type); | |
1722 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); | |
1723 EXPECT_EQ(initiator->session->remote_name(), kResponder); | |
1724 EXPECT_EQ(initiator->session->local_description(), offer); | |
1725 | |
1726 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1727 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
1728 initiator->session_state()); | |
1729 initiator->ExpectSentStanza( | |
1730 IqSet("0", kInitiator, kResponder, initiate_xml)); | |
1731 | |
1732 // Expect transport-info message from initiator. | |
1733 initiator->DeliverAckToLastStanza(); | |
1734 initiator->PrepareCandidates(); | |
1735 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1736 initiator->ExpectSentStanza( | |
1737 IqSet("1", kInitiator, kResponder, transport_info_xml)); | |
1738 | |
1739 // Send a redirect to the initiator and expect all of the message | |
1740 // to be resent. | |
1741 const buzz::XmlElement* initiate_stanza = initiator->stanza(); | |
1742 rtc::scoped_ptr<buzz::XmlElement> redirect_stanza( | |
1743 buzz::XmlElement::ForStr( | |
1744 IqError("ER2", kResponder, kInitiator, | |
1745 RedirectXml(protocol, initiate_xml, responder_full)))); | |
1746 initiator->session_manager->OnFailedSend( | |
1747 initiate_stanza, redirect_stanza.get()); | |
1748 EXPECT_EQ(initiator->session->remote_name(), responder_full); | |
1749 | |
1750 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1751 initiator->ExpectSentStanza( | |
1752 IqSet("2", kInitiator, responder_full, initiate_xml)); | |
1753 initiator->ExpectSentStanza( | |
1754 IqSet("3", kInitiator, responder_full, transport_info_xml)); | |
1755 | |
1756 // Deliver the initiate. Expect ack and session created with | |
1757 // transports. | |
1758 responder->DeliverStanza( | |
1759 IqSet("2", kInitiator, responder_full, initiate_xml)); | |
1760 responder->ExpectSentStanza( | |
1761 IqAck("2", responder_full, kInitiator)); | |
1762 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1763 | |
1764 EXPECT_EQ(1U, responder->session_created_count); | |
1765 EXPECT_EQ(kSessionId, responder->session->id()); | |
1766 EXPECT_EQ(responder->session->local_name(), responder_full); | |
1767 EXPECT_EQ(responder->session->remote_name(), kInitiator); | |
1768 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
1769 responder->session_state()); | |
1770 | |
1771 EXPECT_TRUE(responder->HasChannel(content_name, 1)); | |
1772 EXPECT_TRUE(responder->HasChannel(content_name, 2)); | |
1773 | |
1774 // Deliver transport-info and expect ack. | |
1775 responder->DeliverStanza( | |
1776 IqSet("3", kInitiator, responder_full, transport_info_xml)); | |
1777 responder->ExpectSentStanza( | |
1778 IqAck("3", responder_full, kInitiator)); | |
1779 | |
1780 // Expect reply transport-infos sent to new remote JID | |
1781 responder->PrepareCandidates(); | |
1782 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); | |
1783 responder->ExpectSentStanza( | |
1784 IqSet("4", responder_full, kInitiator, transport_info_reply_xml)); | |
1785 | |
1786 initiator->DeliverStanza(responder->stanza()); | |
1787 initiator->ExpectSentStanza( | |
1788 IqAck("4", kInitiator, responder_full)); | |
1789 | |
1790 // The channels should be able to become writable at this point. This | |
1791 // requires pinging, so it may take a little while. | |
1792 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && | |
1793 initiator->chan_a->readable(), kEventTimeout); | |
1794 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && | |
1795 initiator->chan_b->readable(), kEventTimeout); | |
1796 EXPECT_TRUE_WAIT(responder->chan_a->writable() && | |
1797 responder->chan_a->readable(), kEventTimeout); | |
1798 EXPECT_TRUE_WAIT(responder->chan_b->writable() && | |
1799 responder->chan_b->readable(), kEventTimeout); | |
1800 | |
1801 // Accept the session and expect accept stanza. | |
1802 cricket::SessionDescription* answer = NewTestSessionDescription( | |
1803 content_name, content_type); | |
1804 EXPECT_TRUE(responder->session->Accept(answer)); | |
1805 EXPECT_EQ(responder->session->local_description(), answer); | |
1806 | |
1807 responder->ExpectSentStanza( | |
1808 IqSet("5", responder_full, kInitiator, accept_xml)); | |
1809 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1810 | |
1811 // Deliver the accept message and expect an ack. | |
1812 initiator->DeliverStanza(responder->stanza()); | |
1813 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1814 initiator->ExpectSentStanza( | |
1815 IqAck("5", kInitiator, responder_full)); | |
1816 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1817 | |
1818 // Both sessions should be in progress and have functioning | |
1819 // channels. | |
1820 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1821 initiator->session_state(), kEventTimeout); | |
1822 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1823 responder->session_state(), kEventTimeout); | |
1824 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), | |
1825 responder->chan_a.get(), responder->chan_b.get()); | |
1826 } | |
1827 | |
1828 void TestCandidatesInInitiateAndAccept(const std::string& test_name) { | |
1829 std::string content_name = "main"; | |
1830 std::string content_type = "http://oink.splat/session"; | |
1831 std::string channel_name_a = "rtp"; | |
1832 std::string channel_name_b = "rtcp"; | |
1833 cricket::SignalingProtocol protocol = PROTOCOL_JINGLE; | |
1834 | |
1835 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
1836 new TestPortAllocator()); | |
1837 int next_message_id = 0; | |
1838 | |
1839 rtc::scoped_ptr<TestClient> initiator( | |
1840 new TestClient(allocator.get(), &next_message_id, | |
1841 kInitiator, protocol, | |
1842 content_type, | |
1843 content_name, channel_name_a, | |
1844 content_name, channel_name_b)); | |
1845 | |
1846 rtc::scoped_ptr<TestClient> responder( | |
1847 new TestClient(allocator.get(), &next_message_id, | |
1848 kResponder, protocol, | |
1849 content_type, | |
1850 content_name, channel_name_a, | |
1851 content_name, channel_name_b)); | |
1852 | |
1853 // Create Session and check channels and state. | |
1854 initiator->CreateSession(); | |
1855 EXPECT_TRUE(initiator->HasTransport(content_name)); | |
1856 EXPECT_TRUE(initiator->HasChannel(content_name, 1)); | |
1857 EXPECT_TRUE(initiator->HasTransport(content_name)); | |
1858 EXPECT_TRUE(initiator->HasChannel(content_name, 2)); | |
1859 | |
1860 // Initiate and expect initiate message sent. | |
1861 cricket::SessionDescription* offer = NewTestSessionDescription( | |
1862 content_name, content_type); | |
1863 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); | |
1864 | |
1865 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1866 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
1867 initiator->session_state()); | |
1868 initiator->ExpectSentStanza( | |
1869 IqSet("0", kInitiator, kResponder, | |
1870 InitiateXml(protocol, content_name, content_type))); | |
1871 | |
1872 // Fake the delivery the initiate and candidates together. | |
1873 responder->DeliverStanza( | |
1874 IqSet("A", kInitiator, kResponder, | |
1875 JingleInitiateActionXml( | |
1876 JingleContentXml( | |
1877 content_name, content_type, kTransportType, | |
1878 P2pCandidateXml(channel_name_a, 0) + | |
1879 P2pCandidateXml(channel_name_a, 1) + | |
1880 P2pCandidateXml(channel_name_b, 2) + | |
1881 P2pCandidateXml(channel_name_b, 3))))); | |
1882 responder->ExpectSentStanza( | |
1883 IqAck("A", kResponder, kInitiator)); | |
1884 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1885 | |
1886 EXPECT_EQ(1U, responder->session_created_count); | |
1887 EXPECT_EQ(kSessionId, responder->session->id()); | |
1888 EXPECT_EQ(responder->session->local_name(), kResponder); | |
1889 EXPECT_EQ(responder->session->remote_name(), kInitiator); | |
1890 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
1891 responder->session_state()); | |
1892 | |
1893 EXPECT_TRUE(responder->HasTransport(content_name)); | |
1894 EXPECT_TRUE(responder->HasChannel(content_name, 1)); | |
1895 EXPECT_TRUE(responder->HasTransport(content_name)); | |
1896 EXPECT_TRUE(responder->HasChannel(content_name, 2)); | |
1897 | |
1898 // Expect transport-info message from initiator. | |
1899 // But don't send candidates until initiate ack is received. | |
1900 initiator->DeliverAckToLastStanza(); | |
1901 initiator->PrepareCandidates(); | |
1902 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1903 initiator->ExpectSentStanza( | |
1904 IqSet("1", kInitiator, kResponder, | |
1905 TransportInfo4Xml(protocol, content_name, | |
1906 channel_name_a, 0, 1, | |
1907 channel_name_b, 2, 3))); | |
1908 | |
1909 responder->PrepareCandidates(); | |
1910 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); | |
1911 responder->ExpectSentStanza( | |
1912 IqSet("2", kResponder, kInitiator, | |
1913 TransportInfo4Xml(protocol, content_name, | |
1914 channel_name_a, 4, 5, | |
1915 channel_name_b, 6, 7))); | |
1916 | |
1917 // Accept the session and expect accept stanza. | |
1918 cricket::SessionDescription* answer = NewTestSessionDescription( | |
1919 content_name, content_type); | |
1920 EXPECT_TRUE(responder->session->Accept(answer)); | |
1921 | |
1922 responder->ExpectSentStanza( | |
1923 IqSet("3", kResponder, kInitiator, | |
1924 AcceptXml(protocol, content_name, content_type))); | |
1925 EXPECT_EQ(0U, responder->sent_stanza_count()); | |
1926 | |
1927 // Fake the delivery the accept and candidates together. | |
1928 initiator->DeliverStanza( | |
1929 IqSet("B", kResponder, kInitiator, | |
1930 JingleActionXml("session-accept", | |
1931 JingleContentXml( | |
1932 content_name, content_type, kTransportType, | |
1933 P2pCandidateXml(channel_name_a, 4) + | |
1934 P2pCandidateXml(channel_name_a, 5) + | |
1935 P2pCandidateXml(channel_name_b, 6) + | |
1936 P2pCandidateXml(channel_name_b, 7))))); | |
1937 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); | |
1938 initiator->ExpectSentStanza( | |
1939 IqAck("B", kInitiator, kResponder)); | |
1940 EXPECT_EQ(0U, initiator->sent_stanza_count()); | |
1941 | |
1942 // The channels should be able to become writable at this point. This | |
1943 // requires pinging, so it may take a little while. | |
1944 EXPECT_TRUE_WAIT(initiator->chan_a->writable() && | |
1945 initiator->chan_a->readable(), kEventTimeout); | |
1946 EXPECT_TRUE_WAIT(initiator->chan_b->writable() && | |
1947 initiator->chan_b->readable(), kEventTimeout); | |
1948 EXPECT_TRUE_WAIT(responder->chan_a->writable() && | |
1949 responder->chan_a->readable(), kEventTimeout); | |
1950 EXPECT_TRUE_WAIT(responder->chan_b->writable() && | |
1951 responder->chan_b->readable(), kEventTimeout); | |
1952 | |
1953 | |
1954 // Both sessions should be in progress and have functioning | |
1955 // channels. | |
1956 EXPECT_EQ(protocol, initiator->session->current_protocol()); | |
1957 EXPECT_EQ(protocol, responder->session->current_protocol()); | |
1958 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1959 initiator->session_state(), kEventTimeout); | |
1960 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, | |
1961 responder->session_state(), kEventTimeout); | |
1962 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), | |
1963 responder->chan_a.get(), responder->chan_b.get()); | |
1964 } | |
1965 | |
1966 // Tests that when an initiator terminates right after initiate, | |
1967 // everything behaves correctly. | |
1968 void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) { | |
1969 std::string content_name = "main"; | |
1970 std::string content_type = "http://oink.splat/session"; | |
1971 | |
1972 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
1973 new TestPortAllocator()); | |
1974 int next_message_id = 0; | |
1975 | |
1976 rtc::scoped_ptr<TestClient> initiator( | |
1977 new TestClient(allocator.get(), &next_message_id, | |
1978 kInitiator, protocol, | |
1979 content_type, | |
1980 content_name, "a", | |
1981 content_name, "b")); | |
1982 | |
1983 rtc::scoped_ptr<TestClient> responder( | |
1984 new TestClient(allocator.get(), &next_message_id, | |
1985 kResponder, protocol, | |
1986 content_type, | |
1987 content_name, "a", | |
1988 content_name, "b")); | |
1989 | |
1990 // Send initiate | |
1991 initiator->CreateSession(); | |
1992 EXPECT_TRUE(initiator->session->Initiate( | |
1993 kResponder, NewTestSessionDescription(content_name, content_type))); | |
1994 initiator->ExpectSentStanza( | |
1995 IqSet("0", kInitiator, kResponder, | |
1996 InitiateXml(protocol, content_name, content_type))); | |
1997 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
1998 initiator->session_state()); | |
1999 | |
2000 responder->DeliverStanza(initiator->stanza()); | |
2001 responder->ExpectSentStanza( | |
2002 IqAck("0", kResponder, kInitiator)); | |
2003 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
2004 responder->session_state()); | |
2005 | |
2006 initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR); | |
2007 initiator->ExpectSentStanza( | |
2008 IqSet("1", kInitiator, kResponder, | |
2009 TerminateXml(protocol, cricket::STR_TERMINATE_ERROR))); | |
2010 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, | |
2011 initiator->session_state()); | |
2012 | |
2013 responder->DeliverStanza(initiator->stanza()); | |
2014 responder->ExpectSentStanza( | |
2015 IqAck("1", kResponder, kInitiator)); | |
2016 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, | |
2017 responder->session_state()); | |
2018 } | |
2019 | |
2020 // Tests that when the responder rejects, everything behaves | |
2021 // correctly. | |
2022 void TestRejection(SignalingProtocol protocol) { | |
2023 std::string content_name = "main"; | |
2024 std::string content_type = "http://oink.splat/session"; | |
2025 | |
2026 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
2027 new TestPortAllocator()); | |
2028 int next_message_id = 0; | |
2029 | |
2030 rtc::scoped_ptr<TestClient> initiator( | |
2031 new TestClient(allocator.get(), &next_message_id, | |
2032 kInitiator, protocol, | |
2033 content_type, | |
2034 content_name, "a", | |
2035 content_name, "b")); | |
2036 | |
2037 // Send initiate | |
2038 initiator->CreateSession(); | |
2039 EXPECT_TRUE(initiator->session->Initiate( | |
2040 kResponder, NewTestSessionDescription(content_name, content_type))); | |
2041 initiator->ExpectSentStanza( | |
2042 IqSet("0", kInitiator, kResponder, | |
2043 InitiateXml(protocol, content_name, content_type))); | |
2044 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, | |
2045 initiator->session_state()); | |
2046 | |
2047 initiator->DeliverStanza( | |
2048 IqSet("1", kResponder, kInitiator, | |
2049 RejectXml(protocol, cricket::STR_TERMINATE_ERROR))); | |
2050 initiator->ExpectSentStanza( | |
2051 IqAck("1", kInitiator, kResponder)); | |
2052 if (protocol == PROTOCOL_JINGLE) { | |
2053 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, | |
2054 initiator->session_state()); | |
2055 } else { | |
2056 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT, | |
2057 initiator->session_state()); | |
2058 } | |
2059 } | |
2060 | |
2061 void TestTransportMux() { | |
2062 SignalingProtocol initiator_protocol = PROTOCOL_JINGLE; | |
2063 SignalingProtocol responder_protocol = PROTOCOL_JINGLE; | |
2064 SignalingProtocol resulting_protocol = PROTOCOL_JINGLE; | |
2065 std::string content_type = cricket::NS_JINGLE_RTP; | |
2066 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; | |
2067 std::string content_name_a = cricket::CN_AUDIO; | |
2068 std::string channel_name_a = "rtp"; | |
2069 std::string content_name_b = cricket::CN_VIDEO; | |
2070 std::string channel_name_b = "video_rtp"; | |
2071 | |
2072 std::string initiate_xml = InitiateXml( | |
2073 initiator_protocol, | |
2074 gingle_content_type, | |
2075 content_name_a, content_type, | |
2076 content_name_b, content_type, true); | |
2077 std::string transport_info_a_xml = TransportInfo2Xml( | |
2078 initiator_protocol, content_name_a, | |
2079 channel_name_a, 0, 1); | |
2080 std::string transport_info_b_xml = TransportInfo2Xml( | |
2081 initiator_protocol, content_name_b, | |
2082 channel_name_b, 2, 3); | |
2083 std::string transport_info_reply_a_xml = TransportInfo2Xml( | |
2084 resulting_protocol, content_name_a, | |
2085 channel_name_a, 4, 5); | |
2086 std::string transport_info_reply_b_xml = TransportInfo2Xml( | |
2087 resulting_protocol, content_name_b, | |
2088 channel_name_b, 6, 7); | |
2089 std::string accept_xml = AcceptXml( | |
2090 resulting_protocol, | |
2091 gingle_content_type, | |
2092 content_name_a, content_type, | |
2093 content_name_b, content_type, true); | |
2094 | |
2095 TestSession(initiator_protocol, responder_protocol, resulting_protocol, | |
2096 gingle_content_type, | |
2097 content_type, | |
2098 content_name_a, channel_name_a, | |
2099 content_name_b, channel_name_b, | |
2100 initiate_xml, | |
2101 transport_info_a_xml, transport_info_b_xml, | |
2102 transport_info_reply_a_xml, transport_info_reply_b_xml, | |
2103 accept_xml, | |
2104 true); | |
2105 } | |
2106 | |
2107 void TestSendDescriptionInfo() { | |
2108 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
2109 new TestPortAllocator()); | |
2110 int next_message_id = 0; | |
2111 | |
2112 std::string content_name = "content-name"; | |
2113 std::string content_type = "content-type"; | |
2114 rtc::scoped_ptr<TestClient> initiator( | |
2115 new TestClient(allocator.get(), &next_message_id, | |
2116 kInitiator, PROTOCOL_JINGLE, | |
2117 content_type, | |
2118 content_name, "", | |
2119 "", "")); | |
2120 | |
2121 initiator->CreateSession(); | |
2122 cricket::SessionDescription* offer = NewTestSessionDescription( | |
2123 content_name, content_type); | |
2124 std::string initiate_xml = InitiateXml( | |
2125 PROTOCOL_JINGLE, content_name, content_type); | |
2126 | |
2127 cricket::ContentInfos contents; | |
2128 TestContentDescription content(content_type, content_type); | |
2129 contents.push_back( | |
2130 cricket::ContentInfo(content_name, content_type, &content)); | |
2131 std::string description_info_xml = JingleDescriptionInfoXml( | |
2132 content_name, content_type); | |
2133 | |
2134 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); | |
2135 initiator->ExpectSentStanza( | |
2136 IqSet("0", kInitiator, kResponder, initiate_xml)); | |
2137 | |
2138 EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents)); | |
2139 initiator->ExpectSentStanza( | |
2140 IqSet("1", kInitiator, kResponder, description_info_xml)); | |
2141 } | |
2142 | |
2143 void DoTestSignalNewDescription( | |
2144 TestClient* client, | |
2145 cricket::BaseSession::State state, | |
2146 cricket::ContentAction expected_content_action, | |
2147 cricket::ContentSource expected_content_source) { | |
2148 // Clean up before the new test. | |
2149 client->new_local_description = false; | |
2150 client->new_remote_description = false; | |
2151 | |
2152 client->SetSessionState(state); | |
2153 EXPECT_EQ((expected_content_source == cricket::CS_LOCAL), | |
2154 client->new_local_description); | |
2155 EXPECT_EQ((expected_content_source == cricket::CS_REMOTE), | |
2156 client->new_remote_description); | |
2157 EXPECT_EQ(expected_content_action, client->last_content_action); | |
2158 EXPECT_EQ(expected_content_source, client->last_content_source); | |
2159 } | |
2160 | |
2161 void TestCallerSignalNewDescription() { | |
2162 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
2163 new TestPortAllocator()); | |
2164 int next_message_id = 0; | |
2165 | |
2166 std::string content_name = "content-name"; | |
2167 std::string content_type = "content-type"; | |
2168 rtc::scoped_ptr<TestClient> initiator( | |
2169 new TestClient(allocator.get(), &next_message_id, | |
2170 kInitiator, PROTOCOL_JINGLE, | |
2171 content_type, | |
2172 content_name, "", | |
2173 "", "")); | |
2174 | |
2175 initiator->CreateSession(); | |
2176 | |
2177 // send offer -> send update offer -> | |
2178 // receive pr answer -> receive update pr answer -> | |
2179 // receive answer | |
2180 DoTestSignalNewDescription( | |
2181 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, | |
2182 cricket::CA_OFFER, cricket::CS_LOCAL); | |
2183 | |
2184 DoTestSignalNewDescription( | |
2185 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, | |
2186 cricket::CA_OFFER, cricket::CS_LOCAL); | |
2187 | |
2188 DoTestSignalNewDescription( | |
2189 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, | |
2190 cricket::CA_PRANSWER, cricket::CS_REMOTE); | |
2191 | |
2192 DoTestSignalNewDescription( | |
2193 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, | |
2194 cricket::CA_PRANSWER, cricket::CS_REMOTE); | |
2195 | |
2196 DoTestSignalNewDescription( | |
2197 initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT, | |
2198 cricket::CA_ANSWER, cricket::CS_REMOTE); | |
2199 } | |
2200 | |
2201 void TestCalleeSignalNewDescription() { | |
2202 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
2203 new TestPortAllocator()); | |
2204 int next_message_id = 0; | |
2205 | |
2206 std::string content_name = "content-name"; | |
2207 std::string content_type = "content-type"; | |
2208 rtc::scoped_ptr<TestClient> initiator( | |
2209 new TestClient(allocator.get(), &next_message_id, | |
2210 kInitiator, PROTOCOL_JINGLE, | |
2211 content_type, | |
2212 content_name, "", | |
2213 "", "")); | |
2214 | |
2215 initiator->CreateSession(); | |
2216 | |
2217 // receive offer -> receive update offer -> | |
2218 // send pr answer -> send update pr answer -> | |
2219 // send answer | |
2220 DoTestSignalNewDescription( | |
2221 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
2222 cricket::CA_OFFER, cricket::CS_REMOTE); | |
2223 | |
2224 DoTestSignalNewDescription( | |
2225 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, | |
2226 cricket::CA_OFFER, cricket::CS_REMOTE); | |
2227 | |
2228 DoTestSignalNewDescription( | |
2229 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, | |
2230 cricket::CA_PRANSWER, cricket::CS_LOCAL); | |
2231 | |
2232 DoTestSignalNewDescription( | |
2233 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, | |
2234 cricket::CA_PRANSWER, cricket::CS_LOCAL); | |
2235 | |
2236 DoTestSignalNewDescription( | |
2237 initiator.get(), cricket::BaseSession::STATE_SENTACCEPT, | |
2238 cricket::CA_ANSWER, cricket::CS_LOCAL); | |
2239 } | |
2240 | |
2241 void TestGetTransportStats() { | |
2242 rtc::scoped_ptr<cricket::PortAllocator> allocator( | |
2243 new TestPortAllocator()); | |
2244 int next_message_id = 0; | |
2245 | |
2246 std::string content_name = "content-name"; | |
2247 std::string content_type = "content-type"; | |
2248 rtc::scoped_ptr<TestClient> initiator( | |
2249 new TestClient(allocator.get(), &next_message_id, | |
2250 kInitiator, PROTOCOL_JINGLE, | |
2251 content_type, | |
2252 content_name, "", | |
2253 "", "")); | |
2254 initiator->CreateSession(); | |
2255 | |
2256 cricket::SessionStats stats; | |
2257 EXPECT_TRUE(initiator->session->GetStats(&stats)); | |
2258 // At initiation, there are 2 transports. | |
2259 EXPECT_EQ(2ul, stats.proxy_to_transport.size()); | |
2260 EXPECT_EQ(2ul, stats.transport_stats.size()); | |
2261 } | |
2262 }; | |
2263 | |
2264 // For each of these, "X => Y = Z" means "if a client with protocol X | |
2265 // initiates to a client with protocol Y, they end up speaking protocol Z. | |
2266 | |
2267 // Gingle => Gingle = Gingle (with other content) | |
2268 TEST_F(SessionTest, GingleToGingleOtherContent) { | |
2269 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2270 } | |
2271 | |
2272 // Gingle => Gingle = Gingle (with audio content) | |
2273 TEST_F(SessionTest, GingleToGingleAudioContent) { | |
2274 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2275 } | |
2276 | |
2277 // Gingle => Gingle = Gingle (with video contents) | |
2278 TEST_F(SessionTest, GingleToGingleVideoContents) { | |
2279 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2280 } | |
2281 | |
2282 // Jingle => Jingle = Jingle (with other content) | |
2283 TEST_F(SessionTest, JingleToJingleOtherContent) { | |
2284 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2285 } | |
2286 | |
2287 // Jingle => Jingle = Jingle (with audio content) | |
2288 TEST_F(SessionTest, JingleToJingleAudioContent) { | |
2289 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2290 } | |
2291 | |
2292 // Jingle => Jingle = Jingle (with video contents) | |
2293 TEST_F(SessionTest, JingleToJingleVideoContents) { | |
2294 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2295 } | |
2296 | |
2297 // Hybrid => Hybrid = Jingle (with other content) | |
2298 TEST_F(SessionTest, HybridToHybridOtherContent) { | |
2299 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2300 } | |
2301 | |
2302 // Hybrid => Hybrid = Jingle (with audio content) | |
2303 TEST_F(SessionTest, HybridToHybridAudioContent) { | |
2304 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2305 } | |
2306 | |
2307 // Hybrid => Hybrid = Jingle (with video contents) | |
2308 TEST_F(SessionTest, HybridToHybridVideoContents) { | |
2309 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2310 } | |
2311 | |
2312 // Gingle => Hybrid = Gingle (with other content) | |
2313 TEST_F(SessionTest, GingleToHybridOtherContent) { | |
2314 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); | |
2315 } | |
2316 | |
2317 // Gingle => Hybrid = Gingle (with audio content) | |
2318 TEST_F(SessionTest, GingleToHybridAudioContent) { | |
2319 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); | |
2320 } | |
2321 | |
2322 // Gingle => Hybrid = Gingle (with video contents) | |
2323 TEST_F(SessionTest, GingleToHybridVideoContents) { | |
2324 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); | |
2325 } | |
2326 | |
2327 // Jingle => Hybrid = Jingle (with other content) | |
2328 TEST_F(SessionTest, JingleToHybridOtherContent) { | |
2329 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2330 } | |
2331 | |
2332 // Jingle => Hybrid = Jingle (with audio content) | |
2333 TEST_F(SessionTest, JingleToHybridAudioContent) { | |
2334 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2335 } | |
2336 | |
2337 // Jingle => Hybrid = Jingle (with video contents) | |
2338 TEST_F(SessionTest, JingleToHybridVideoContents) { | |
2339 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); | |
2340 } | |
2341 | |
2342 // Hybrid => Gingle = Gingle (with other content) | |
2343 TEST_F(SessionTest, HybridToGingleOtherContent) { | |
2344 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2345 } | |
2346 | |
2347 // Hybrid => Gingle = Gingle (with audio content) | |
2348 TEST_F(SessionTest, HybridToGingleAudioContent) { | |
2349 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2350 } | |
2351 | |
2352 // Hybrid => Gingle = Gingle (with video contents) | |
2353 TEST_F(SessionTest, HybridToGingleVideoContents) { | |
2354 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); | |
2355 } | |
2356 | |
2357 // Hybrid => Jingle = Jingle (with other content) | |
2358 TEST_F(SessionTest, HybridToJingleOtherContent) { | |
2359 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2360 } | |
2361 | |
2362 // Hybrid => Jingle = Jingle (with audio content) | |
2363 TEST_F(SessionTest, HybridToJingleAudioContent) { | |
2364 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2365 } | |
2366 | |
2367 // Hybrid => Jingle = Jingle (with video contents) | |
2368 TEST_F(SessionTest, HybridToJingleVideoContents) { | |
2369 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); | |
2370 } | |
2371 | |
2372 TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) { | |
2373 TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE); | |
2374 } | |
2375 | |
2376 TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) { | |
2377 TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE); | |
2378 } | |
2379 | |
2380 TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) { | |
2381 TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID); | |
2382 } | |
2383 | |
2384 TEST_F(SessionTest, GingleRejection) { | |
2385 TestRejection(PROTOCOL_GINGLE); | |
2386 } | |
2387 | |
2388 TEST_F(SessionTest, JingleRejection) { | |
2389 TestRejection(PROTOCOL_JINGLE); | |
2390 } | |
2391 | |
2392 TEST_F(SessionTest, GingleGoodRedirect) { | |
2393 TestGoodRedirect(PROTOCOL_GINGLE); | |
2394 } | |
2395 | |
2396 TEST_F(SessionTest, JingleGoodRedirect) { | |
2397 TestGoodRedirect(PROTOCOL_JINGLE); | |
2398 } | |
2399 | |
2400 TEST_F(SessionTest, GingleBadRedirect) { | |
2401 TestBadRedirect(PROTOCOL_GINGLE); | |
2402 } | |
2403 | |
2404 TEST_F(SessionTest, JingleBadRedirect) { | |
2405 TestBadRedirect(PROTOCOL_JINGLE); | |
2406 } | |
2407 | |
2408 TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) { | |
2409 TestCandidatesInInitiateAndAccept("Candidates in initiate/accept"); | |
2410 } | |
2411 | |
2412 TEST_F(SessionTest, TestTransportMux) { | |
2413 TestTransportMux(); | |
2414 } | |
2415 | |
2416 TEST_F(SessionTest, TestSendDescriptionInfo) { | |
2417 TestSendDescriptionInfo(); | |
2418 } | |
2419 | |
2420 TEST_F(SessionTest, TestCallerSignalNewDescription) { | |
2421 TestCallerSignalNewDescription(); | |
2422 } | |
2423 | |
2424 TEST_F(SessionTest, TestCalleeSignalNewDescription) { | |
2425 TestCalleeSignalNewDescription(); | |
2426 } | |
2427 | |
2428 TEST_F(SessionTest, TestGetTransportStats) { | |
2429 TestGetTransportStats(); | |
2430 } | |
OLD | NEW |