Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "signaling/src/sdp/SdpAttribute.h"
8 : #include "signaling/src/sdp/SdpHelper.h"
9 : #include <iomanip>
10 :
11 : #ifdef CRLF
12 : #undef CRLF
13 : #endif
14 : #define CRLF "\r\n"
15 :
16 : namespace mozilla
17 : {
18 :
19 : static unsigned char
20 0 : PeekChar(std::istream& is, std::string* error)
21 : {
22 0 : int next = is.peek();
23 0 : if (next == EOF) {
24 0 : *error = "Truncated";
25 0 : return 0;
26 : }
27 :
28 0 : return next;
29 : }
30 :
31 0 : static std::string ParseToken(std::istream& is,
32 : const std::string& delims,
33 : std::string* error)
34 : {
35 0 : std::string token;
36 0 : while (is) {
37 0 : unsigned char c = PeekChar(is, error);
38 0 : if (!c || (delims.find(c) != std::string::npos)) {
39 0 : break;
40 : }
41 0 : token.push_back(std::tolower(is.get()));
42 : }
43 0 : return token;
44 : }
45 :
46 : static bool
47 0 : SkipChar(std::istream& is, unsigned char c, std::string* error)
48 : {
49 0 : if (PeekChar(is, error) != c) {
50 0 : *error = "Expected \'";
51 0 : error->push_back(c);
52 0 : error->push_back('\'');
53 0 : return false;
54 : }
55 :
56 0 : is.get();
57 0 : return true;
58 : }
59 :
60 :
61 : void
62 0 : SdpConnectionAttribute::Serialize(std::ostream& os) const
63 : {
64 0 : os << "a=" << mType << ":" << mValue << CRLF;
65 0 : }
66 :
67 : void
68 0 : SdpDirectionAttribute::Serialize(std::ostream& os) const
69 : {
70 0 : os << "a=" << mValue << CRLF;
71 0 : }
72 :
73 : void
74 0 : SdpDtlsMessageAttribute::Serialize(std::ostream& os) const
75 : {
76 0 : os << "a=" << mType << ":" << mRole << " " << mValue << CRLF;
77 0 : }
78 :
79 : bool
80 0 : SdpDtlsMessageAttribute::Parse(std::istream& is, std::string* error)
81 : {
82 0 : std::string roleToken = ParseToken(is, " ", error);
83 0 : if (roleToken == "server") {
84 0 : mRole = kServer;
85 0 : } else if (roleToken == "client") {
86 0 : mRole = kClient;
87 : } else {
88 0 : *error = "Invalid dtls-message role; must be either client or server";
89 0 : return false;
90 : }
91 :
92 0 : is >> std::ws;
93 :
94 0 : std::string s(std::istreambuf_iterator<char>(is), {});
95 0 : mValue = s;
96 :
97 0 : return true;
98 : }
99 :
100 : void
101 0 : SdpExtmapAttributeList::Serialize(std::ostream& os) const
102 : {
103 0 : for (auto i = mExtmaps.begin(); i != mExtmaps.end(); ++i) {
104 0 : os << "a=" << mType << ":" << i->entry;
105 0 : if (i->direction_specified) {
106 0 : os << "/" << i->direction;
107 : }
108 0 : os << " " << i->extensionname;
109 0 : if (i->extensionattributes.length()) {
110 0 : os << " " << i->extensionattributes;
111 : }
112 0 : os << CRLF;
113 : }
114 0 : }
115 :
116 : void
117 0 : SdpFingerprintAttributeList::Serialize(std::ostream& os) const
118 : {
119 0 : for (auto i = mFingerprints.begin(); i != mFingerprints.end(); ++i) {
120 0 : os << "a=" << mType << ":" << i->hashFunc << " "
121 0 : << FormatFingerprint(i->fingerprint) << CRLF;
122 : }
123 0 : }
124 :
125 : // Format the fingerprint in RFC 4572 Section 5 attribute format
126 : std::string
127 0 : SdpFingerprintAttributeList::FormatFingerprint(const std::vector<uint8_t>& fp)
128 : {
129 0 : if (fp.empty()) {
130 0 : MOZ_ASSERT(false, "Cannot format an empty fingerprint.");
131 : return "";
132 : }
133 :
134 0 : std::ostringstream os;
135 0 : for (auto i = fp.begin(); i != fp.end(); ++i) {
136 0 : os << ":" << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
137 0 : << static_cast<uint32_t>(*i);
138 : }
139 0 : return os.str().substr(1);
140 : }
141 :
142 : static uint8_t
143 0 : FromUppercaseHex(char ch)
144 : {
145 0 : if ((ch >= '0') && (ch <= '9')) {
146 0 : return ch - '0';
147 : }
148 0 : if ((ch >= 'A') && (ch <= 'F')) {
149 0 : return ch - 'A' + 10;
150 : }
151 0 : return 16; // invalid
152 : }
153 :
154 : // Parse the fingerprint from RFC 4572 Section 5 attribute format
155 : std::vector<uint8_t>
156 0 : SdpFingerprintAttributeList::ParseFingerprint(const std::string& str)
157 : {
158 0 : size_t targetSize = (str.length() + 1) / 3;
159 0 : std::vector<uint8_t> fp(targetSize);
160 0 : size_t fpIndex = 0;
161 :
162 0 : if (str.length() % 3 != 2) {
163 0 : fp.clear();
164 0 : return fp;
165 : }
166 :
167 0 : for (size_t i = 0; i < str.length(); i += 3) {
168 0 : uint8_t high = FromUppercaseHex(str[i]);
169 0 : uint8_t low = FromUppercaseHex(str[i + 1]);
170 0 : if (high > 0xf || low > 0xf ||
171 0 : (i + 2 < str.length() && str[i + 2] != ':')) {
172 0 : fp.clear(); // error
173 0 : return fp;
174 : }
175 0 : fp[fpIndex++] = high << 4 | low;
176 : }
177 0 : return fp;
178 : }
179 :
180 : void
181 0 : SdpFmtpAttributeList::Serialize(std::ostream& os) const
182 : {
183 0 : for (auto i = mFmtps.begin(); i != mFmtps.end(); ++i) {
184 0 : if (i->parameters) {
185 0 : os << "a=" << mType << ":" << i->format << " ";
186 0 : i->parameters->Serialize(os);
187 0 : os << CRLF;
188 : }
189 : }
190 0 : }
191 :
192 : void
193 0 : SdpGroupAttributeList::Serialize(std::ostream& os) const
194 : {
195 0 : for (auto i = mGroups.begin(); i != mGroups.end(); ++i) {
196 0 : os << "a=" << mType << ":" << i->semantics;
197 0 : for (auto j = i->tags.begin(); j != i->tags.end(); ++j) {
198 0 : os << " " << (*j);
199 : }
200 0 : os << CRLF;
201 : }
202 0 : }
203 :
204 : // We're just using an SdpStringAttribute for this right now
205 : #if 0
206 : void SdpIdentityAttribute::Serialize(std::ostream& os) const
207 : {
208 : os << "a=" << mType << ":" << mAssertion;
209 : for (auto i = mExtensions.begin(); i != mExtensions.end(); i++) {
210 : os << (i == mExtensions.begin() ? " " : ";") << (*i);
211 : }
212 : os << CRLF;
213 : }
214 : #endif
215 :
216 : // Class to help with omitting a leading delimiter for the first item in a list
217 0 : class SkipFirstDelimiter
218 : {
219 : public:
220 0 : explicit SkipFirstDelimiter(const std::string& delim) :
221 : mDelim(delim),
222 0 : mFirst(true)
223 0 : {}
224 :
225 0 : std::ostream& print(std::ostream& os)
226 : {
227 0 : if (!mFirst) {
228 0 : os << mDelim;
229 : }
230 0 : mFirst = false;
231 0 : return os;
232 : }
233 :
234 : private:
235 : std::string mDelim;
236 : bool mFirst;
237 : };
238 :
239 0 : static std::ostream& operator<<(std::ostream& os, SkipFirstDelimiter& delim)
240 : {
241 0 : return delim.print(os);
242 : }
243 :
244 : void
245 0 : SdpImageattrAttributeList::XYRange::Serialize(std::ostream& os) const
246 : {
247 0 : if (discreteValues.size() == 0) {
248 0 : os << "[" << min << ":";
249 0 : if (step != 1) {
250 0 : os << step << ":";
251 : }
252 0 : os << max << "]";
253 0 : } else if (discreteValues.size() == 1) {
254 0 : os << discreteValues.front();
255 : } else {
256 0 : os << "[";
257 0 : SkipFirstDelimiter comma(",");
258 0 : for (auto value : discreteValues) {
259 0 : os << comma << value;
260 : }
261 0 : os << "]";
262 : }
263 0 : }
264 :
265 : template<typename T>
266 : bool
267 0 : GetUnsigned(std::istream& is, T min, T max, T* value, std::string* error)
268 : {
269 0 : if (PeekChar(is, error) == '-') {
270 0 : *error = "Value is less than 0";
271 0 : return false;
272 : }
273 :
274 0 : is >> std::noskipws >> *value;
275 :
276 0 : if (is.fail()) {
277 0 : *error = "Malformed";
278 0 : return false;
279 : }
280 :
281 0 : if (*value < min) {
282 0 : *error = "Value too small";
283 0 : return false;
284 : }
285 :
286 0 : if (*value > max) {
287 0 : *error = "Value too large";
288 0 : return false;
289 : }
290 :
291 0 : return true;
292 : }
293 :
294 : static bool
295 0 : GetXYValue(std::istream& is, uint32_t* value, std::string* error)
296 : {
297 0 : return GetUnsigned<uint32_t>(is, 1, 999999, value, error);
298 : }
299 :
300 : bool
301 0 : SdpImageattrAttributeList::XYRange::ParseDiscreteValues(std::istream& is,
302 : std::string* error)
303 : {
304 0 : do {
305 : uint32_t value;
306 0 : if (!GetXYValue(is, &value, error)) {
307 0 : return false;
308 : }
309 0 : discreteValues.push_back(value);
310 : } while (SkipChar(is, ',', error));
311 :
312 0 : return SkipChar(is, ']', error);
313 : }
314 :
315 : bool
316 0 : SdpImageattrAttributeList::XYRange::ParseAfterMin(std::istream& is,
317 : std::string* error)
318 : {
319 : // We have already parsed "[320:", and now expect another uint
320 : uint32_t value;
321 0 : if (!GetXYValue(is, &value, error)) {
322 0 : return false;
323 : }
324 :
325 0 : if (SkipChar(is, ':', error)) {
326 : // Range with step eg [320:16:640]
327 0 : step = value;
328 : // Now |value| should be the max
329 0 : if (!GetXYValue(is, &value, error)) {
330 0 : return false;
331 : }
332 : }
333 :
334 0 : max = value;
335 0 : if (min >= max) {
336 0 : *error = "Min is not smaller than max";
337 0 : return false;
338 : }
339 :
340 0 : return SkipChar(is, ']', error);
341 : }
342 :
343 : bool
344 0 : SdpImageattrAttributeList::XYRange::ParseAfterBracket(std::istream& is,
345 : std::string* error)
346 : {
347 : // Either a range, or a list of discrete values
348 : // [320:640], [320:16:640], or [320,640]
349 : uint32_t value;
350 0 : if (!GetXYValue(is, &value, error)) {
351 0 : return false;
352 : }
353 :
354 0 : if (SkipChar(is, ':', error)) {
355 : // Range - [640:480] or [640:16:480]
356 0 : min = value;
357 0 : return ParseAfterMin(is, error);
358 : }
359 :
360 0 : if (SkipChar(is, ',', error)) {
361 0 : discreteValues.push_back(value);
362 0 : return ParseDiscreteValues(is, error);
363 : }
364 :
365 0 : *error = "Expected \':\' or \',\'";
366 0 : return false;
367 : }
368 :
369 : bool
370 0 : SdpImageattrAttributeList::XYRange::Parse(std::istream& is, std::string* error)
371 : {
372 0 : if (SkipChar(is, '[', error)) {
373 0 : return ParseAfterBracket(is, error);
374 : }
375 :
376 : // Single discrete value
377 : uint32_t value;
378 0 : if (!GetXYValue(is, &value, error)) {
379 0 : return false;
380 : }
381 0 : discreteValues.push_back(value);
382 :
383 0 : return true;
384 : }
385 :
386 : static bool
387 0 : GetSPValue(std::istream& is, float* value, std::string* error)
388 : {
389 0 : return GetUnsigned<float>(is, 0.1f, 9.9999f, value, error);
390 : }
391 :
392 : static bool
393 0 : GetQValue(std::istream& is, float* value, std::string* error)
394 : {
395 0 : return GetUnsigned<float>(is, 0.0f, 1.0f, value, error);
396 : }
397 :
398 : bool
399 0 : SdpImageattrAttributeList::SRange::ParseDiscreteValues(std::istream& is,
400 : std::string* error)
401 : {
402 0 : do {
403 : float value;
404 0 : if (!GetSPValue(is, &value, error)) {
405 0 : return false;
406 : }
407 0 : discreteValues.push_back(value);
408 : } while (SkipChar(is, ',', error));
409 :
410 0 : return SkipChar(is, ']', error);
411 : }
412 :
413 : bool
414 0 : SdpImageattrAttributeList::SRange::ParseAfterMin(std::istream& is,
415 : std::string* error)
416 : {
417 0 : if (!GetSPValue(is, &max, error)) {
418 0 : return false;
419 : }
420 :
421 0 : if (min >= max) {
422 0 : *error = "Min is not smaller than max";
423 0 : return false;
424 : }
425 :
426 0 : return SkipChar(is, ']', error);
427 : }
428 :
429 : bool
430 0 : SdpImageattrAttributeList::SRange::ParseAfterBracket(std::istream& is,
431 : std::string* error)
432 : {
433 : // Either a range, or a list of discrete values
434 : float value;
435 0 : if (!GetSPValue(is, &value, error)) {
436 0 : return false;
437 : }
438 :
439 0 : if (SkipChar(is, '-', error)) {
440 0 : min = value;
441 0 : return ParseAfterMin(is, error);
442 : }
443 :
444 0 : if (SkipChar(is, ',', error)) {
445 0 : discreteValues.push_back(value);
446 0 : return ParseDiscreteValues(is, error);
447 : }
448 :
449 0 : *error = "Expected either \'-\' or \',\'";
450 0 : return false;
451 : }
452 :
453 : bool
454 0 : SdpImageattrAttributeList::SRange::Parse(std::istream& is, std::string* error)
455 : {
456 0 : if (SkipChar(is, '[', error)) {
457 0 : return ParseAfterBracket(is, error);
458 : }
459 :
460 : // Single discrete value
461 : float value;
462 0 : if (!GetSPValue(is, &value, error)) {
463 0 : return false;
464 : }
465 0 : discreteValues.push_back(value);
466 0 : return true;
467 : }
468 :
469 : bool
470 0 : SdpImageattrAttributeList::PRange::Parse(std::istream& is, std::string* error)
471 : {
472 0 : if (!SkipChar(is, '[', error)) {
473 0 : return false;
474 : }
475 :
476 0 : if (!GetSPValue(is, &min, error)) {
477 0 : return false;
478 : }
479 :
480 0 : if (!SkipChar(is, '-', error)) {
481 0 : return false;
482 : }
483 :
484 0 : if (!GetSPValue(is, &max, error)) {
485 0 : return false;
486 : }
487 :
488 0 : if (min >= max) {
489 0 : *error = "min must be smaller than max";
490 0 : return false;
491 : }
492 :
493 0 : if (!SkipChar(is, ']', error)) {
494 0 : return false;
495 : }
496 0 : return true;
497 : }
498 :
499 : void
500 0 : SdpImageattrAttributeList::SRange::Serialize(std::ostream& os) const
501 : {
502 0 : os << std::setprecision(4) << std::fixed;
503 0 : if (discreteValues.size() == 0) {
504 0 : os << "[" << min << "-" << max << "]";
505 0 : } else if (discreteValues.size() == 1) {
506 0 : os << discreteValues.front();
507 : } else {
508 0 : os << "[";
509 0 : SkipFirstDelimiter comma(",");
510 0 : for (auto value : discreteValues) {
511 0 : os << comma << value;
512 : }
513 0 : os << "]";
514 : }
515 0 : }
516 :
517 : void
518 0 : SdpImageattrAttributeList::PRange::Serialize(std::ostream& os) const
519 : {
520 0 : os << std::setprecision(4) << std::fixed;
521 0 : os << "[" << min << "-" << max << "]";
522 0 : }
523 :
524 0 : static std::string ParseKey(std::istream& is, std::string* error)
525 : {
526 0 : std::string token = ParseToken(is, "=", error);
527 0 : if (!SkipChar(is, '=', error)) {
528 0 : return "";
529 : }
530 0 : return token;
531 : }
532 :
533 0 : static bool SkipBraces(std::istream& is, std::string* error)
534 : {
535 0 : if (PeekChar(is, error) != '[') {
536 0 : *error = "Expected \'[\'";
537 0 : return false;
538 : }
539 :
540 0 : size_t braceCount = 0;
541 0 : do {
542 0 : switch (PeekChar(is, error)) {
543 : case '[':
544 0 : ++braceCount;
545 0 : break;
546 : case ']':
547 0 : --braceCount;
548 0 : break;
549 : default:
550 0 : break;
551 : }
552 0 : is.get();
553 0 : } while (braceCount && is);
554 :
555 0 : if (!is) {
556 0 : *error = "Expected closing brace";
557 0 : return false;
558 : }
559 :
560 0 : return true;
561 : }
562 :
563 : // Assumptions:
564 : // 1. If the value contains '[' or ']', they are balanced.
565 : // 2. The value contains no ',' outside of brackets.
566 0 : static bool SkipValue(std::istream& is, std::string* error)
567 : {
568 0 : while (is) {
569 0 : switch (PeekChar(is, error)) {
570 : case ',':
571 : case ']':
572 0 : return true;
573 : case '[':
574 0 : if (!SkipBraces(is, error)) {
575 0 : return false;
576 : }
577 0 : break;
578 : default:
579 0 : is.get();
580 : }
581 : }
582 :
583 0 : *error = "No closing \']\' on set";
584 0 : return false;
585 : }
586 :
587 : bool
588 0 : SdpImageattrAttributeList::Set::Parse(std::istream& is, std::string* error)
589 : {
590 0 : if (!SkipChar(is, '[', error)) {
591 0 : return false;
592 : }
593 :
594 0 : if (ParseKey(is, error) != "x") {
595 0 : *error = "Expected x=";
596 0 : return false;
597 : }
598 :
599 0 : if (!xRange.Parse(is, error)) {
600 0 : return false;
601 : }
602 :
603 0 : if (!SkipChar(is, ',', error)) {
604 0 : return false;
605 : }
606 :
607 0 : if (ParseKey(is, error) != "y") {
608 0 : *error = "Expected y=";
609 0 : return false;
610 : }
611 :
612 0 : if (!yRange.Parse(is, error)) {
613 0 : return false;
614 : }
615 :
616 0 : qValue = 0.5f; // default
617 :
618 0 : bool gotSar = false;
619 0 : bool gotPar = false;
620 0 : bool gotQ = false;
621 :
622 0 : while (SkipChar(is, ',', error)) {
623 0 : std::string key = ParseKey(is, error);
624 0 : if (key.empty()) {
625 0 : *error = "Expected key-value";
626 0 : return false;
627 : }
628 :
629 0 : if (key == "sar") {
630 0 : if (gotSar) {
631 0 : *error = "Extra sar parameter";
632 0 : return false;
633 : }
634 0 : gotSar = true;
635 0 : if (!sRange.Parse(is, error)) {
636 0 : return false;
637 : }
638 0 : } else if (key == "par") {
639 0 : if (gotPar) {
640 0 : *error = "Extra par parameter";
641 0 : return false;
642 : }
643 0 : gotPar = true;
644 0 : if (!pRange.Parse(is, error)) {
645 0 : return false;
646 : }
647 0 : } else if (key == "q") {
648 0 : if (gotQ) {
649 0 : *error = "Extra q parameter";
650 0 : return false;
651 : }
652 0 : gotQ = true;
653 0 : if (!GetQValue(is, &qValue, error)) {
654 0 : return false;
655 : }
656 : } else {
657 0 : if (!SkipValue(is, error)) {
658 0 : return false;
659 : }
660 : }
661 : }
662 :
663 0 : return SkipChar(is, ']', error);
664 : }
665 :
666 : void
667 0 : SdpImageattrAttributeList::Set::Serialize(std::ostream& os) const
668 : {
669 0 : os << "[x=";
670 0 : xRange.Serialize(os);
671 0 : os << ",y=";
672 0 : yRange.Serialize(os);
673 0 : if (sRange.IsSet()) {
674 0 : os << ",sar=";
675 0 : sRange.Serialize(os);
676 : }
677 0 : if (pRange.IsSet()) {
678 0 : os << ",par=";
679 0 : pRange.Serialize(os);
680 : }
681 0 : if (qValue >= 0) {
682 0 : os << std::setprecision(2) << std::fixed << ",q=" << qValue;
683 : }
684 0 : os << "]";
685 0 : }
686 :
687 : bool
688 0 : SdpImageattrAttributeList::Imageattr::ParseSets(std::istream& is,
689 : std::string* error)
690 : {
691 0 : std::string type = ParseToken(is, " \t", error);
692 :
693 0 : bool* isAll = nullptr;
694 0 : std::vector<Set>* sets = nullptr;
695 :
696 0 : if (type == "send") {
697 0 : isAll = &sendAll;
698 0 : sets = &sendSets;
699 0 : } else if (type == "recv") {
700 0 : isAll = &recvAll;
701 0 : sets = &recvSets;
702 : } else {
703 0 : *error = "Unknown type, must be either send or recv";
704 0 : return false;
705 : }
706 :
707 0 : if (*isAll || !sets->empty()) {
708 0 : *error = "Multiple send or recv set lists";
709 0 : return false;
710 : }
711 :
712 0 : is >> std::ws;
713 0 : if (SkipChar(is, '*', error)) {
714 0 : *isAll = true;
715 0 : return true;
716 : }
717 :
718 0 : do {
719 0 : Set set;
720 0 : if (!set.Parse(is, error)) {
721 0 : return false;
722 : }
723 :
724 0 : sets->push_back(set);
725 0 : is >> std::ws;
726 0 : } while (PeekChar(is, error) == '[');
727 :
728 0 : return true;
729 : }
730 :
731 : bool
732 0 : SdpImageattrAttributeList::Imageattr::Parse(std::istream& is,
733 : std::string* error)
734 : {
735 0 : if (!SkipChar(is, '*', error)) {
736 : uint16_t value;
737 0 : if (!GetUnsigned<uint16_t>(is, 0, UINT16_MAX, &value, error)) {
738 0 : return false;
739 : }
740 0 : pt = Some(value);
741 : }
742 :
743 0 : is >> std::ws;
744 0 : if (!ParseSets(is, error)) {
745 0 : return false;
746 : }
747 :
748 : // There might be a second one
749 0 : is >> std::ws;
750 0 : if (is.eof()) {
751 0 : return true;
752 : }
753 :
754 0 : if (!ParseSets(is, error)) {
755 0 : return false;
756 : }
757 :
758 0 : is >> std::ws;
759 0 : if (!is.eof()) {
760 0 : *error = "Trailing characters";
761 0 : return false;
762 : }
763 :
764 0 : return true;
765 : }
766 :
767 : void
768 0 : SdpImageattrAttributeList::Imageattr::Serialize(std::ostream& os) const
769 : {
770 0 : if (pt.isSome()) {
771 0 : os << *pt;
772 : } else {
773 0 : os << "*";
774 : }
775 :
776 0 : if (sendAll) {
777 0 : os << " send *";
778 0 : } else if (!sendSets.empty()) {
779 0 : os << " send";
780 0 : for (auto& set : sendSets) {
781 0 : os << " ";
782 0 : set.Serialize(os);
783 : }
784 : }
785 :
786 0 : if (recvAll) {
787 0 : os << " recv *";
788 0 : } else if (!recvSets.empty()) {
789 0 : os << " recv";
790 0 : for (auto& set : recvSets) {
791 0 : os << " ";
792 0 : set.Serialize(os);
793 : }
794 : }
795 0 : }
796 :
797 : void
798 0 : SdpImageattrAttributeList::Serialize(std::ostream& os) const
799 : {
800 0 : for (auto& imageattr : mImageattrs) {
801 0 : os << "a=" << mType << ":";
802 0 : imageattr.Serialize(os);
803 0 : os << CRLF;
804 : }
805 0 : }
806 :
807 : bool
808 0 : SdpImageattrAttributeList::PushEntry(const std::string& raw,
809 : std::string* error,
810 : size_t* errorPos)
811 : {
812 0 : std::istringstream is(raw);
813 :
814 0 : Imageattr imageattr;
815 0 : if (!imageattr.Parse(is, error)) {
816 0 : is.clear();
817 0 : *errorPos = is.tellg();
818 0 : return false;
819 : }
820 :
821 0 : mImageattrs.push_back(imageattr);
822 0 : return true;
823 : }
824 :
825 : void
826 0 : SdpMsidAttributeList::Serialize(std::ostream& os) const
827 : {
828 0 : for (auto i = mMsids.begin(); i != mMsids.end(); ++i) {
829 0 : os << "a=" << mType << ":" << i->identifier;
830 0 : if (i->appdata.length()) {
831 0 : os << " " << i->appdata;
832 : }
833 0 : os << CRLF;
834 : }
835 0 : }
836 :
837 : void
838 0 : SdpMsidSemanticAttributeList::Serialize(std::ostream& os) const
839 : {
840 0 : for (auto i = mMsidSemantics.begin(); i != mMsidSemantics.end(); ++i) {
841 0 : os << "a=" << mType << ":" << i->semantic;
842 0 : for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
843 0 : os << " " << *j;
844 : }
845 0 : os << CRLF;
846 : }
847 0 : }
848 :
849 : void
850 0 : SdpRemoteCandidatesAttribute::Serialize(std::ostream& os) const
851 : {
852 0 : if (mCandidates.empty()) {
853 0 : return;
854 : }
855 :
856 0 : os << "a=" << mType;
857 0 : for (auto i = mCandidates.begin(); i != mCandidates.end(); i++) {
858 0 : os << (i == mCandidates.begin() ? ":" : " ") << i->id << " " << i->address
859 0 : << " " << i->port;
860 : }
861 0 : os << CRLF;
862 : }
863 :
864 : bool
865 0 : SdpRidAttributeList::Rid::ParseParameters(std::istream& is, std::string* error)
866 : {
867 0 : if (!PeekChar(is, error)) {
868 : // No parameters
869 0 : return true;
870 : }
871 :
872 0 : do {
873 0 : is >> std::ws;
874 0 : std::string key = ParseKey(is, error);
875 0 : if (key.empty()) {
876 0 : return false; // Illegal trailing cruft
877 : }
878 :
879 : // This allows pt= to appear anywhere, instead of only at the beginning, but
880 : // this ends up being significantly less code.
881 0 : if (key == "pt") {
882 0 : if (!ParseFormats(is, error)) {
883 0 : return false;
884 : }
885 0 : } else if (key == "max-width") {
886 0 : if (!GetUnsigned<uint32_t>(
887 : is, 0, UINT32_MAX, &constraints.maxWidth, error)) {
888 0 : return false;
889 : }
890 0 : } else if (key == "max-height") {
891 0 : if (!GetUnsigned<uint32_t>(
892 : is, 0, UINT32_MAX, &constraints.maxHeight, error)) {
893 0 : return false;
894 : }
895 0 : } else if (key == "max-fps") {
896 0 : if (!GetUnsigned<uint32_t>(
897 : is, 0, UINT32_MAX, &constraints.maxFps, error)) {
898 0 : return false;
899 : }
900 0 : } else if (key == "max-fs") {
901 0 : if (!GetUnsigned<uint32_t>(
902 : is, 0, UINT32_MAX, &constraints.maxFs, error)) {
903 0 : return false;
904 : }
905 0 : } else if (key == "max-br") {
906 0 : if (!GetUnsigned<uint32_t>(
907 : is, 0, UINT32_MAX, &constraints.maxBr, error)) {
908 0 : return false;
909 : }
910 0 : } else if (key == "max-pps") {
911 0 : if (!GetUnsigned<uint32_t>(
912 : is, 0, UINT32_MAX, &constraints.maxPps, error)) {
913 0 : return false;
914 : }
915 0 : } else if (key == "depend") {
916 0 : if (!ParseDepend(is, error)) {
917 0 : return false;
918 : }
919 : } else {
920 0 : (void) ParseToken(is, ";", error);
921 : }
922 : } while (SkipChar(is, ';', error));
923 0 : return true;
924 : }
925 :
926 : bool
927 0 : SdpRidAttributeList::Rid::ParseDepend(
928 : std::istream& is,
929 : std::string* error)
930 : {
931 0 : do {
932 0 : std::string id = ParseToken(is, ",;", error);
933 0 : if (id.empty()) {
934 0 : return false;
935 : }
936 0 : dependIds.push_back(id);
937 : } while(SkipChar(is, ',', error));
938 :
939 0 : return true;
940 : }
941 :
942 : bool
943 0 : SdpRidAttributeList::Rid::ParseFormats(
944 : std::istream& is,
945 : std::string* error)
946 : {
947 0 : do {
948 : uint16_t fmt;
949 0 : if (!GetUnsigned<uint16_t>(is, 0, 127, &fmt, error)) {
950 0 : return false;
951 : }
952 0 : formats.push_back(fmt);
953 : } while (SkipChar(is, ',', error));
954 :
955 0 : return true;
956 : }
957 :
958 : void
959 0 : SdpRidAttributeList::Rid::SerializeParameters(std::ostream& os) const
960 : {
961 0 : if (!HasParameters()) {
962 0 : return;
963 : }
964 :
965 0 : os << " ";
966 :
967 0 : SkipFirstDelimiter semic(";");
968 :
969 0 : if (!formats.empty()) {
970 0 : os << semic << "pt=";
971 0 : SkipFirstDelimiter comma(",");
972 0 : for (uint16_t fmt : formats) {
973 0 : os << comma << fmt;
974 : }
975 : }
976 :
977 0 : if (constraints.maxWidth) {
978 0 : os << semic << "max-width=" << constraints.maxWidth;
979 : }
980 :
981 0 : if (constraints.maxHeight) {
982 0 : os << semic << "max-height=" << constraints.maxHeight;
983 : }
984 :
985 0 : if (constraints.maxFps) {
986 0 : os << semic << "max-fps=" << constraints.maxFps;
987 : }
988 :
989 0 : if (constraints.maxFs) {
990 0 : os << semic << "max-fs=" << constraints.maxFs;
991 : }
992 :
993 0 : if (constraints.maxBr) {
994 0 : os << semic << "max-br=" << constraints.maxBr;
995 : }
996 :
997 0 : if (constraints.maxPps) {
998 0 : os << semic << "max-pps=" << constraints.maxPps;
999 : }
1000 :
1001 0 : if (!dependIds.empty()) {
1002 0 : os << semic << "depend=";
1003 0 : SkipFirstDelimiter comma(",");
1004 0 : for (const std::string& id : dependIds) {
1005 0 : os << comma << id;
1006 : }
1007 : }
1008 : }
1009 :
1010 : bool
1011 0 : SdpRidAttributeList::Rid::Parse(std::istream& is, std::string* error)
1012 : {
1013 0 : id = ParseToken(is, " ", error);
1014 0 : if (id.empty()) {
1015 0 : return false;
1016 : }
1017 :
1018 0 : is >> std::ws;
1019 0 : std::string directionToken = ParseToken(is, " ", error);
1020 0 : if (directionToken == "send") {
1021 0 : direction = sdp::kSend;
1022 0 : } else if (directionToken == "recv") {
1023 0 : direction = sdp::kRecv;
1024 : } else {
1025 0 : *error = "Invalid direction, must be either send or recv";
1026 0 : return false;
1027 : }
1028 :
1029 0 : return ParseParameters(is, error);
1030 : }
1031 :
1032 : void
1033 0 : SdpRidAttributeList::Rid::Serialize(std::ostream& os) const
1034 : {
1035 0 : os << id << " " << direction;
1036 0 : SerializeParameters(os);
1037 0 : }
1038 :
1039 : bool
1040 0 : SdpRidAttributeList::Rid::HasFormat(const std::string& format) const
1041 : {
1042 0 : if (formats.empty()) {
1043 0 : return true;
1044 : }
1045 :
1046 : uint16_t formatAsInt;
1047 0 : if (!SdpHelper::GetPtAsInt(format, &formatAsInt)) {
1048 0 : return false;
1049 : }
1050 :
1051 0 : return (std::find(formats.begin(), formats.end(), formatAsInt) !=
1052 0 : formats.end());
1053 : }
1054 :
1055 : void
1056 0 : SdpRidAttributeList::Serialize(std::ostream& os) const
1057 : {
1058 0 : for (const Rid& rid : mRids) {
1059 0 : os << "a=" << mType << ":";
1060 0 : rid.Serialize(os);
1061 0 : os << CRLF;
1062 : }
1063 0 : }
1064 :
1065 : bool
1066 0 : SdpRidAttributeList::PushEntry(const std::string& raw,
1067 : std::string* error,
1068 : size_t* errorPos)
1069 : {
1070 0 : std::istringstream is(raw);
1071 :
1072 0 : Rid rid;
1073 0 : if (!rid.Parse(is, error)) {
1074 0 : is.clear();
1075 0 : *errorPos = is.tellg();
1076 0 : return false;
1077 : }
1078 :
1079 0 : mRids.push_back(rid);
1080 0 : return true;
1081 : }
1082 :
1083 : void
1084 0 : SdpRtcpAttribute::Serialize(std::ostream& os) const
1085 : {
1086 0 : os << "a=" << mType << ":" << mPort;
1087 0 : if (!mAddress.empty()) {
1088 0 : os << " " << mNetType << " " << mAddrType << " " << mAddress;
1089 : }
1090 0 : os << CRLF;
1091 0 : }
1092 :
1093 : const char* SdpRtcpFbAttributeList::pli = "pli";
1094 : const char* SdpRtcpFbAttributeList::sli = "sli";
1095 : const char* SdpRtcpFbAttributeList::rpsi = "rpsi";
1096 : const char* SdpRtcpFbAttributeList::app = "app";
1097 :
1098 : const char* SdpRtcpFbAttributeList::fir = "fir";
1099 : const char* SdpRtcpFbAttributeList::tmmbr = "tmmbr";
1100 : const char* SdpRtcpFbAttributeList::tstr = "tstr";
1101 : const char* SdpRtcpFbAttributeList::vbcm = "vbcm";
1102 :
1103 : void
1104 0 : SdpRtcpFbAttributeList::Serialize(std::ostream& os) const
1105 : {
1106 0 : for (auto i = mFeedbacks.begin(); i != mFeedbacks.end(); ++i) {
1107 0 : os << "a=" << mType << ":" << i->pt << " " << i->type;
1108 0 : if (i->parameter.length()) {
1109 0 : os << " " << i->parameter;
1110 0 : if (i->extra.length()) {
1111 0 : os << " " << i->extra;
1112 : }
1113 : }
1114 0 : os << CRLF;
1115 : }
1116 0 : }
1117 :
1118 : static bool
1119 0 : ShouldSerializeChannels(SdpRtpmapAttributeList::CodecType type)
1120 : {
1121 0 : switch (type) {
1122 : case SdpRtpmapAttributeList::kOpus:
1123 : case SdpRtpmapAttributeList::kG722:
1124 0 : return true;
1125 : case SdpRtpmapAttributeList::kPCMU:
1126 : case SdpRtpmapAttributeList::kPCMA:
1127 : case SdpRtpmapAttributeList::kVP8:
1128 : case SdpRtpmapAttributeList::kVP9:
1129 : case SdpRtpmapAttributeList::kiLBC:
1130 : case SdpRtpmapAttributeList::kiSAC:
1131 : case SdpRtpmapAttributeList::kH264:
1132 : case SdpRtpmapAttributeList::kRed:
1133 : case SdpRtpmapAttributeList::kUlpfec:
1134 : case SdpRtpmapAttributeList::kTelephoneEvent:
1135 0 : return false;
1136 : case SdpRtpmapAttributeList::kOtherCodec:
1137 0 : return true;
1138 : }
1139 0 : MOZ_CRASH();
1140 : }
1141 :
1142 : void
1143 0 : SdpRtpmapAttributeList::Serialize(std::ostream& os) const
1144 : {
1145 0 : for (auto i = mRtpmaps.begin(); i != mRtpmaps.end(); ++i) {
1146 0 : os << "a=" << mType << ":" << i->pt << " " << i->name << "/" << i->clock;
1147 0 : if (i->channels && ShouldSerializeChannels(i->codec)) {
1148 0 : os << "/" << i->channels;
1149 : }
1150 0 : os << CRLF;
1151 : }
1152 0 : }
1153 :
1154 : void
1155 0 : SdpSctpmapAttributeList::Serialize(std::ostream& os) const
1156 : {
1157 0 : for (auto i = mSctpmaps.begin(); i != mSctpmaps.end(); ++i) {
1158 0 : os << "a=" << mType << ":" << i->pt << " " << i->name << " " << i->streams
1159 0 : << CRLF;
1160 : }
1161 0 : }
1162 :
1163 : void
1164 0 : SdpSetupAttribute::Serialize(std::ostream& os) const
1165 : {
1166 0 : os << "a=" << mType << ":" << mRole << CRLF;
1167 0 : }
1168 :
1169 : void
1170 0 : SdpSimulcastAttribute::Version::Serialize(std::ostream& os) const
1171 : {
1172 0 : SkipFirstDelimiter comma(",");
1173 0 : for (const std::string& choice : choices) {
1174 0 : os << comma << choice;
1175 : }
1176 0 : }
1177 :
1178 : bool
1179 0 : SdpSimulcastAttribute::Version::Parse(std::istream& is, std::string* error)
1180 : {
1181 0 : do {
1182 0 : std::string value = ParseToken(is, ",; ", error);
1183 0 : if (value.empty()) {
1184 0 : return false;
1185 : }
1186 0 : choices.push_back(value);
1187 : } while (SkipChar(is, ',', error));
1188 :
1189 0 : return true;
1190 : }
1191 :
1192 : bool
1193 0 : SdpSimulcastAttribute::Version::GetChoicesAsFormats(
1194 : std::vector<uint16_t>* formats) const
1195 : {
1196 0 : for (const std::string& choice : choices) {
1197 : uint16_t format;
1198 0 : if (!SdpHelper::GetPtAsInt(choice, &format) || (format > 127)) {
1199 0 : return false;
1200 : }
1201 0 : formats->push_back(format);
1202 : }
1203 :
1204 0 : return true;
1205 : }
1206 :
1207 : void
1208 0 : SdpSimulcastAttribute::Versions::Serialize(std::ostream& os) const
1209 : {
1210 0 : switch (type) {
1211 : case kRid:
1212 0 : os << "rid=";
1213 0 : break;
1214 : case kPt:
1215 0 : os << "pt=";
1216 0 : break;
1217 : }
1218 :
1219 0 : SkipFirstDelimiter semic(";");
1220 0 : for (const Version& version : *this) {
1221 0 : if (!version.IsSet()) {
1222 0 : continue;
1223 : }
1224 0 : os << semic;
1225 0 : version.Serialize(os);
1226 : }
1227 0 : }
1228 :
1229 : bool
1230 0 : SdpSimulcastAttribute::Versions::Parse(std::istream& is, std::string* error)
1231 : {
1232 0 : std::string rawType = ParseKey(is, error);
1233 0 : if (rawType.empty()) {
1234 0 : return false;
1235 : }
1236 :
1237 0 : if (rawType == "pt") {
1238 0 : type = kPt;
1239 0 : } else if (rawType == "rid") {
1240 0 : type = kRid;
1241 : } else {
1242 0 : *error = "Unknown simulcast identification type ";
1243 0 : error->append(rawType);
1244 0 : return false;
1245 : }
1246 :
1247 0 : do {
1248 0 : Version version;
1249 0 : if (!version.Parse(is, error)) {
1250 0 : return false;
1251 : }
1252 :
1253 0 : if (type == kPt) {
1254 0 : std::vector<uint16_t> formats;
1255 0 : if (!version.GetChoicesAsFormats(&formats)) {
1256 0 : *error = "Invalid payload type";
1257 0 : return false;
1258 : }
1259 : }
1260 :
1261 0 : push_back(version);
1262 : } while(SkipChar(is, ';', error));
1263 :
1264 0 : return true;
1265 : }
1266 :
1267 : void
1268 0 : SdpSimulcastAttribute::Serialize(std::ostream& os) const
1269 : {
1270 0 : MOZ_ASSERT(sendVersions.IsSet() || recvVersions.IsSet());
1271 :
1272 0 : os << "a=" << mType << ":";
1273 :
1274 0 : if (sendVersions.IsSet()) {
1275 0 : os << " send ";
1276 0 : sendVersions.Serialize(os);
1277 : }
1278 :
1279 0 : if (recvVersions.IsSet()) {
1280 0 : os << " recv ";
1281 0 : recvVersions.Serialize(os);
1282 : }
1283 :
1284 0 : os << CRLF;
1285 0 : }
1286 :
1287 : bool
1288 0 : SdpSimulcastAttribute::Parse(std::istream& is, std::string* error)
1289 : {
1290 0 : bool gotRecv = false;
1291 0 : bool gotSend = false;
1292 :
1293 : while (true) {
1294 0 : is >> std::ws;
1295 0 : std::string token = ParseToken(is, " \t", error);
1296 0 : if (token.empty()) {
1297 0 : break;
1298 : }
1299 :
1300 0 : if (token == "send") {
1301 0 : if (gotSend) {
1302 0 : *error = "Already got a send list";
1303 0 : return false;
1304 : }
1305 0 : gotSend = true;
1306 :
1307 0 : is >> std::ws;
1308 0 : if (!sendVersions.Parse(is, error)) {
1309 0 : return false;
1310 : }
1311 0 : } else if (token == "recv") {
1312 0 : if (gotRecv) {
1313 0 : *error = "Already got a recv list";
1314 0 : return false;
1315 : }
1316 0 : gotRecv = true;
1317 :
1318 0 : is >> std::ws;
1319 0 : if (!recvVersions.Parse(is, error)) {
1320 0 : return false;
1321 : }
1322 : } else {
1323 0 : *error = "Type must be either 'send' or 'recv'";
1324 0 : return false;
1325 : }
1326 0 : }
1327 :
1328 0 : if (!gotSend && !gotRecv) {
1329 0 : *error = "Empty simulcast attribute";
1330 0 : return false;
1331 : }
1332 :
1333 0 : return true;
1334 : }
1335 :
1336 : void
1337 0 : SdpSsrcAttributeList::Serialize(std::ostream& os) const
1338 : {
1339 0 : for (auto i = mSsrcs.begin(); i != mSsrcs.end(); ++i) {
1340 0 : os << "a=" << mType << ":" << i->ssrc << " " << i->attribute << CRLF;
1341 : }
1342 0 : }
1343 :
1344 : void
1345 0 : SdpSsrcGroupAttributeList::Serialize(std::ostream& os) const
1346 : {
1347 0 : for (auto i = mSsrcGroups.begin(); i != mSsrcGroups.end(); ++i) {
1348 0 : os << "a=" << mType << ":" << i->semantics;
1349 0 : for (auto j = i->ssrcs.begin(); j != i->ssrcs.end(); ++j) {
1350 0 : os << " " << (*j);
1351 : }
1352 0 : os << CRLF;
1353 : }
1354 0 : }
1355 :
1356 : void
1357 0 : SdpMultiStringAttribute::Serialize(std::ostream& os) const
1358 : {
1359 0 : for (auto i = mValues.begin(); i != mValues.end(); ++i) {
1360 0 : os << "a=" << mType << ":" << *i << CRLF;
1361 : }
1362 0 : }
1363 :
1364 : void
1365 0 : SdpOptionsAttribute::Serialize(std::ostream& os) const
1366 : {
1367 0 : if (mValues.empty()) {
1368 0 : return;
1369 : }
1370 :
1371 0 : os << "a=" << mType << ":";
1372 :
1373 0 : for (auto i = mValues.begin(); i != mValues.end(); ++i) {
1374 0 : if (i != mValues.begin()) {
1375 0 : os << " ";
1376 : }
1377 0 : os << *i;
1378 : }
1379 0 : os << CRLF;
1380 : }
1381 :
1382 : void
1383 0 : SdpOptionsAttribute::Load(const std::string& value)
1384 : {
1385 0 : size_t start = 0;
1386 0 : size_t end = value.find(' ');
1387 0 : while (end != std::string::npos) {
1388 0 : PushEntry(value.substr(start, end));
1389 0 : start = end + 1;
1390 0 : end = value.find(' ', start);
1391 : }
1392 0 : PushEntry(value.substr(start));
1393 0 : }
1394 :
1395 : void
1396 0 : SdpFlagAttribute::Serialize(std::ostream& os) const
1397 : {
1398 0 : os << "a=" << mType << CRLF;
1399 0 : }
1400 :
1401 : void
1402 0 : SdpStringAttribute::Serialize(std::ostream& os) const
1403 : {
1404 0 : os << "a=" << mType << ":" << mValue << CRLF;
1405 0 : }
1406 :
1407 : void
1408 0 : SdpNumberAttribute::Serialize(std::ostream& os) const
1409 : {
1410 0 : os << "a=" << mType << ":" << mValue << CRLF;
1411 0 : }
1412 :
1413 : bool
1414 0 : SdpAttribute::IsAllowedAtMediaLevel(AttributeType type)
1415 : {
1416 0 : switch (type) {
1417 : case kBundleOnlyAttribute:
1418 0 : return true;
1419 : case kCandidateAttribute:
1420 0 : return true;
1421 : case kConnectionAttribute:
1422 0 : return true;
1423 : case kDirectionAttribute:
1424 0 : return true;
1425 : case kDtlsMessageAttribute:
1426 0 : return false;
1427 : case kEndOfCandidatesAttribute:
1428 0 : return true;
1429 : case kExtmapAttribute:
1430 0 : return true;
1431 : case kFingerprintAttribute:
1432 0 : return true;
1433 : case kFmtpAttribute:
1434 0 : return true;
1435 : case kGroupAttribute:
1436 0 : return false;
1437 : case kIceLiteAttribute:
1438 0 : return false;
1439 : case kIceMismatchAttribute:
1440 0 : return true;
1441 : // RFC 5245 says this is session-level only, but
1442 : // draft-ietf-mmusic-ice-sip-sdp-03 updates this to allow at the media
1443 : // level.
1444 : case kIceOptionsAttribute:
1445 0 : return true;
1446 : case kIcePwdAttribute:
1447 0 : return true;
1448 : case kIceUfragAttribute:
1449 0 : return true;
1450 : case kIdentityAttribute:
1451 0 : return false;
1452 : case kImageattrAttribute:
1453 0 : return true;
1454 : case kInactiveAttribute:
1455 0 : return true;
1456 : case kLabelAttribute:
1457 0 : return true;
1458 : case kMaxptimeAttribute:
1459 0 : return true;
1460 : case kMidAttribute:
1461 0 : return true;
1462 : case kMsidAttribute:
1463 0 : return true;
1464 : case kMsidSemanticAttribute:
1465 0 : return false;
1466 : case kPtimeAttribute:
1467 0 : return true;
1468 : case kRecvonlyAttribute:
1469 0 : return true;
1470 : case kRemoteCandidatesAttribute:
1471 0 : return true;
1472 : case kRidAttribute:
1473 0 : return true;
1474 : case kRtcpAttribute:
1475 0 : return true;
1476 : case kRtcpFbAttribute:
1477 0 : return true;
1478 : case kRtcpMuxAttribute:
1479 0 : return true;
1480 : case kRtcpRsizeAttribute:
1481 0 : return true;
1482 : case kRtpmapAttribute:
1483 0 : return true;
1484 : case kSctpmapAttribute:
1485 0 : return true;
1486 : case kSendonlyAttribute:
1487 0 : return true;
1488 : case kSendrecvAttribute:
1489 0 : return true;
1490 : case kSetupAttribute:
1491 0 : return true;
1492 : case kSimulcastAttribute:
1493 0 : return true;
1494 : case kSsrcAttribute:
1495 0 : return true;
1496 : case kSsrcGroupAttribute:
1497 0 : return true;
1498 : case kSctpPortAttribute:
1499 0 : return true;
1500 : case kMaxMessageSizeAttribute:
1501 0 : return true;
1502 : }
1503 0 : MOZ_CRASH("Unknown attribute type");
1504 : }
1505 :
1506 : bool
1507 0 : SdpAttribute::IsAllowedAtSessionLevel(AttributeType type)
1508 : {
1509 0 : switch (type) {
1510 : case kBundleOnlyAttribute:
1511 0 : return false;
1512 : case kCandidateAttribute:
1513 0 : return false;
1514 : case kConnectionAttribute:
1515 0 : return true;
1516 : case kDirectionAttribute:
1517 0 : return true;
1518 : case kDtlsMessageAttribute:
1519 0 : return true;
1520 : case kEndOfCandidatesAttribute:
1521 0 : return true;
1522 : case kExtmapAttribute:
1523 0 : return true;
1524 : case kFingerprintAttribute:
1525 0 : return true;
1526 : case kFmtpAttribute:
1527 0 : return false;
1528 : case kGroupAttribute:
1529 0 : return true;
1530 : case kIceLiteAttribute:
1531 0 : return true;
1532 : case kIceMismatchAttribute:
1533 0 : return false;
1534 : case kIceOptionsAttribute:
1535 0 : return true;
1536 : case kIcePwdAttribute:
1537 0 : return true;
1538 : case kIceUfragAttribute:
1539 0 : return true;
1540 : case kIdentityAttribute:
1541 0 : return true;
1542 : case kImageattrAttribute:
1543 0 : return false;
1544 : case kInactiveAttribute:
1545 0 : return true;
1546 : case kLabelAttribute:
1547 0 : return false;
1548 : case kMaxptimeAttribute:
1549 0 : return false;
1550 : case kMidAttribute:
1551 0 : return false;
1552 : case kMsidSemanticAttribute:
1553 0 : return true;
1554 : case kMsidAttribute:
1555 0 : return false;
1556 : case kPtimeAttribute:
1557 0 : return false;
1558 : case kRecvonlyAttribute:
1559 0 : return true;
1560 : case kRemoteCandidatesAttribute:
1561 0 : return false;
1562 : case kRidAttribute:
1563 0 : return false;
1564 : case kRtcpAttribute:
1565 0 : return false;
1566 : case kRtcpFbAttribute:
1567 0 : return false;
1568 : case kRtcpMuxAttribute:
1569 0 : return false;
1570 : case kRtcpRsizeAttribute:
1571 0 : return false;
1572 : case kRtpmapAttribute:
1573 0 : return false;
1574 : case kSctpmapAttribute:
1575 0 : return false;
1576 : case kSendonlyAttribute:
1577 0 : return true;
1578 : case kSendrecvAttribute:
1579 0 : return true;
1580 : case kSetupAttribute:
1581 0 : return true;
1582 : case kSimulcastAttribute:
1583 0 : return false;
1584 : case kSsrcAttribute:
1585 0 : return false;
1586 : case kSsrcGroupAttribute:
1587 0 : return false;
1588 : case kSctpPortAttribute:
1589 0 : return false;
1590 : case kMaxMessageSizeAttribute:
1591 0 : return false;
1592 : }
1593 0 : MOZ_CRASH("Unknown attribute type");
1594 : }
1595 :
1596 : const std::string
1597 0 : SdpAttribute::GetAttributeTypeString(AttributeType type)
1598 : {
1599 0 : switch (type) {
1600 : case kBundleOnlyAttribute:
1601 0 : return "bundle-only";
1602 : case kCandidateAttribute:
1603 0 : return "candidate";
1604 : case kConnectionAttribute:
1605 0 : return "connection";
1606 : case kDtlsMessageAttribute:
1607 0 : return "dtls-message";
1608 : case kEndOfCandidatesAttribute:
1609 0 : return "end-of-candidates";
1610 : case kExtmapAttribute:
1611 0 : return "extmap";
1612 : case kFingerprintAttribute:
1613 0 : return "fingerprint";
1614 : case kFmtpAttribute:
1615 0 : return "fmtp";
1616 : case kGroupAttribute:
1617 0 : return "group";
1618 : case kIceLiteAttribute:
1619 0 : return "ice-lite";
1620 : case kIceMismatchAttribute:
1621 0 : return "ice-mismatch";
1622 : case kIceOptionsAttribute:
1623 0 : return "ice-options";
1624 : case kIcePwdAttribute:
1625 0 : return "ice-pwd";
1626 : case kIceUfragAttribute:
1627 0 : return "ice-ufrag";
1628 : case kIdentityAttribute:
1629 0 : return "identity";
1630 : case kImageattrAttribute:
1631 0 : return "imageattr";
1632 : case kInactiveAttribute:
1633 0 : return "inactive";
1634 : case kLabelAttribute:
1635 0 : return "label";
1636 : case kMaxptimeAttribute:
1637 0 : return "maxptime";
1638 : case kMidAttribute:
1639 0 : return "mid";
1640 : case kMsidAttribute:
1641 0 : return "msid";
1642 : case kMsidSemanticAttribute:
1643 0 : return "msid-semantic";
1644 : case kPtimeAttribute:
1645 0 : return "ptime";
1646 : case kRecvonlyAttribute:
1647 0 : return "recvonly";
1648 : case kRemoteCandidatesAttribute:
1649 0 : return "remote-candidates";
1650 : case kRidAttribute:
1651 0 : return "rid";
1652 : case kRtcpAttribute:
1653 0 : return "rtcp";
1654 : case kRtcpFbAttribute:
1655 0 : return "rtcp-fb";
1656 : case kRtcpMuxAttribute:
1657 0 : return "rtcp-mux";
1658 : case kRtcpRsizeAttribute:
1659 0 : return "rtcp-rsize";
1660 : case kRtpmapAttribute:
1661 0 : return "rtpmap";
1662 : case kSctpmapAttribute:
1663 0 : return "sctpmap";
1664 : case kSendonlyAttribute:
1665 0 : return "sendonly";
1666 : case kSendrecvAttribute:
1667 0 : return "sendrecv";
1668 : case kSetupAttribute:
1669 0 : return "setup";
1670 : case kSimulcastAttribute:
1671 0 : return "simulcast";
1672 : case kSsrcAttribute:
1673 0 : return "ssrc";
1674 : case kSsrcGroupAttribute:
1675 0 : return "ssrc-group";
1676 : case kSctpPortAttribute:
1677 0 : return "sctp-port";
1678 : case kMaxMessageSizeAttribute:
1679 0 : return "max-message-size";
1680 : case kDirectionAttribute:
1681 0 : MOZ_CRASH("kDirectionAttribute not valid here");
1682 : }
1683 0 : MOZ_CRASH("Unknown attribute type");
1684 : }
1685 :
1686 : } // namespace mozilla
|