reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
SdpHelper.cxx
Go to the documentation of this file.
1#include <map>
2#include <utility>
3
4#include "SdpHelper.hxx"
5#include "Sdp.hxx"
6#include "SdpMediaLine.hxx"
7#include "SdpCodec.hxx"
8#include "SdpCandidate.hxx"
9
11
12using namespace resip;
13using namespace sdpcontainer;
14
19
36
38{
39 bool rtcpEnabled = true;
40 Sdp* sdp = new Sdp();
41 const SdpContents::Session* resipSession = &resipSdp.session();
42
43 sdp->setSdpVersion(resipSession->version()); // v=
44
45 sdp->setOriginatorInfo(resipSession->origin().user().c_str(), // o=
46 resipSession->origin().getSessionId(),
47 resipSession->origin().getVersion(),
50 resipSession->origin().getAddress().c_str());
51
52 sdp->setSessionName(resipSession->name().c_str()); // s=
53 sdp->setSessionInformation(resipSession->information().c_str()); // i=
54 if(!resipSession->uri().host().empty())
55 {
56 sdp->setSessionUri(Data::from(resipSession->uri()).c_str()); // u=
57 }
58
59 // Populate email addresses, e=
60 {
61 const std::list<SdpContents::Session::Email>& emails = resipSession->getEmails();
62 std::list<SdpContents::Session::Email>::const_iterator it;
63 for(it = emails.begin(); it != emails.end(); it++)
64 {
65 if(it->getFreeText().empty())
66 {
67 sdp->addEmailAddress(it->getAddress().c_str());
68 }
69 else
70 {
71 sdp->addEmailAddress(Data(it->getAddress() + Data(" (") + it->getFreeText() + Data(")")).c_str());
72 }
73 }
74 }
75
76 // Populate phone numbers, p=
77 {
78 const std::list<SdpContents::Session::Phone>& phones = resipSession->getPhones();
79 std::list<SdpContents::Session::Phone>::const_iterator it;
80 for(it = phones.begin(); it != phones.end(); it++)
81 {
82 if(it->getFreeText().empty())
83 {
84 sdp->addPhoneNumber(it->getNumber().c_str());
85 }
86 else
87 {
88 sdp->addPhoneNumber(Data(it->getNumber() + Data(" (") + it->getFreeText() + Data(")")).c_str());
89 }
90 }
91 }
92
93 // Populate bandwidths, b=
94 {
95 const std::list<SdpContents::Session::Bandwidth>& bandwidths = resipSession->bandwidths();
96 std::list<SdpContents::Session::Bandwidth>::const_iterator it;
97 bool RRSetToZero=false;
98 bool RSSetToZero=false;
99 for(it = bandwidths.begin(); it != bandwidths.end(); it++)
100 {
101 Sdp::SdpBandwidthType type = Sdp::SdpBandwidth::getTypeFromString(it->modifier().c_str());
102 if(type != Sdp::BANDWIDTH_TYPE_NONE)
103 {
104 sdp->addBandwidth(type, it->kbPerSecond());
105 if(type == Sdp::BANDWIDTH_TYPE_RR && it->kbPerSecond() == 0)
106 {
107 RRSetToZero = true;
108 }
109 else if(type == Sdp::BANDWIDTH_TYPE_RS && it->kbPerSecond() == 0)
110 {
111 RSSetToZero = true;
112 }
113 }
114 }
115 // Rtcp if considered disabled if RR and RS are both set to 0
116 if(RRSetToZero && RSSetToZero)
117 {
118 rtcpEnabled = false;
119 }
120 }
121
122 // Populate Times, t=, r=
123 {
124 const std::list<SdpContents::Session::Time>& times = resipSession->getTimes();
125 std::list<SdpContents::Session::Time>::const_iterator it;
126 for(it = times.begin(); it != times.end(); it++)
127 {
128 Sdp::SdpTime *sdpTime = new Sdp::SdpTime(it->getStart(), it->getStop());
129
130 // Add repeats
131 const std::list<SdpContents::Session::Time::Repeat>& repeats = it->getRepeats();
132 std::list<SdpContents::Session::Time::Repeat>::const_iterator it2;
133 for(it2 = repeats.begin(); it2 != repeats.end(); it2++)
134 {
135 Sdp::SdpTime::SdpTimeRepeat* sdpTimeRepeat = new Sdp::SdpTime::SdpTimeRepeat(it2->getInterval(), it2->getDuration());
136
137 // Add offsets
138 const std::list<int>& offsets = it2->getOffsets();
139 std::list<int>::const_iterator it3;
140 for(it3 = offsets.begin(); it3 != offsets.end(); it3++)
141 {
142 sdpTimeRepeat->addOffsetFromStartTime(*it3);
143 }
144 sdpTime->addRepeat(*sdpTimeRepeat);
145 delete sdpTimeRepeat;
146 }
147 sdp->addTime(*sdpTime);
148 delete sdpTime;
149 }
150 }
151
152 // Populate Timezones, z=
153 {
154 const std::list<SdpContents::Session::Timezones::Adjustment> &adjustments = resipSession->getTimezones().getAdjustments();
155 std::list<SdpContents::Session::Timezones::Adjustment>::const_iterator it;
156 for(it = adjustments.begin(); it != adjustments.end(); it++)
157 {
158 sdp->addTimeZone(it->time, it->offset);
159 }
160 }
161
162 // Look for any session level attributes
163 if(resipSession->exists("cat"))
164 {
165 sdp->setCategory(resipSession->getValues("cat").front().c_str());
166 }
167 if(resipSession->exists("keywds"))
168 {
169 sdp->setKeywords(resipSession->getValues("keywds").front().c_str());
170 }
171 if(resipSession->exists("tool"))
172 {
173 sdp->setToolNameAndVersion(resipSession->getValues("tool").front().c_str());
174 }
175 if(resipSession->exists("type"))
176 {
177 sdp->setConferenceType(Sdp::getConferenceTypeFromString(resipSession->getValues("type").front().c_str()));
178 }
179 if(resipSession->exists("charset"))
180 {
181 sdp->setCharSet(resipSession->getValues("charset").front().c_str());
182 }
183 if(resipSession->exists("ice-passive"))
184 {
185 sdp->setIcePassiveOnlyMode(true);
186 }
187 if(resipSession->exists("group"))
188 {
189 const std::list<Data>& values = resipSession->getValues("group");
190 std::list<Data>::const_iterator it;
191 for(it = values.begin(); it != values.end(); it++)
192 {
193 Data token;
194 ParseBuffer pb(*it);
195 const char* anchor = pb.position();
197 if(!pb.eof())
198 {
199 pb.data(token, anchor);
200
202 if(semantics != Sdp::GROUP_SEMANTICS_NONE)
203 {
204 Sdp::SdpGroup* sdpGroup = new Sdp::SdpGroup(semantics);
205 while(!pb.eof())
206 {
207 anchor = pb.skipWhitespace();
209 pb.data(token, anchor);
210 sdpGroup->addIdentificationTag(token.c_str());
211 }
212 sdp->addGroup(*sdpGroup);
213 }
214 }
215 }
216 }
217 if(resipSession->exists("lang"))
218 {
219 sdp->setSessionLanguage(resipSession->getValues("lang").front().c_str());
220 }
221 if(resipSession->exists("sdplang"))
222 {
223 sdp->setDescriptionLanguage(resipSession->getValues("sdplang").front().c_str());
224 }
225 if(resipSession->exists("maxprate"))
226 {
227#ifndef RESIP_FIXED_POINT
228 sdp->setMaximumPacketRate(resipSession->getValues("maxprate").front().convertDouble());
229#else
230// !slg! TODO
231#endif
232 }
233
234 // Iterate through the m= lines
235 const std::list<SdpContents::Session::Medium>& medias = resipSession->media();
236 std::list<SdpContents::Session::Medium>::const_iterator it;
237 for(it = medias.begin(); it != medias.end(); it++)
238 {
239 const SdpContents::Session::Medium& resipMedia = *it;
240 SdpMediaLine* mediaLine = parseMediaLine(resipMedia, *resipSession, rtcpEnabled);
241
242 // Parse out the SDP Capabilities Negotiation Potential Configurations
243 if(resipMedia.exists("pcfg"))
244 {
245 std::list<SdpMediaLine::SdpTransportProtocolCapabilities> tcapList;
246 if(resipMedia.exists("tcap"))
247 {
248 const std::list<Data>& tcaps = resipMedia.getMergedValues("tcap");
249 std::list<Data>::const_iterator it2;
250 for(it2 = tcaps.begin(); it2 != tcaps.end(); it2++)
251 {
253 }
254 }
255 std::map<unsigned int, std::pair<Data, Data> > acapList;
256 if(resipMedia.exists("acap"))
257 {
258 const std::list<Data>& acaps = resipMedia.getMergedValues("acap");
259 std::list<Data>::const_iterator it2;
260 for(it2 = acaps.begin(); it2 != acaps.end(); it2++)
261 {
262 ParseBuffer pb(*it2);
263 unsigned int acapId = pb.uInt32();
264 Data name;
265 Data value;
267 const char * anchor = pb.skipWhitespace();
268 if(!pb.eof())
269 {
271 pb.data(name, anchor);
272 if(!pb.eof())
273 {
274 anchor = pb.skipChar();
275 pb.skipToEnd();
276 pb.data(value, anchor);
277 }
278 }
279 acapList[acapId] = std::make_pair(name, value);
280 }
281 }
282
283 const std::list<Data>& pcfgs = resipMedia.getValues("pcfg");
284 std::list<Data>::const_iterator it2;
285 for (it2 = pcfgs.begin(); it2 != pcfgs.end(); it2++)
286 {
287 Data acceptedConfigurationLine;
288 std::list<SdpMediaLine::SdpPotentialConfiguration> pcfgList;
290 std::list<SdpMediaLine::SdpPotentialConfiguration>::iterator pcfgIt = pcfgList.begin();
291 for (; pcfgIt != pcfgList.end(); pcfgIt++)
292 {
294 if (pcfgIt->getTransportId() != 0)
295 {
296 // Find corresponding transport capability
297 std::list<SdpMediaLine::SdpTransportProtocolCapabilities>::iterator tcapIt = tcapList.begin();
298 for (; tcapIt != tcapList.end(); tcapIt++)
299 {
300 if (tcapIt->getId() == pcfgIt->getTransportId())
301 {
302 potentialTransportType = tcapIt->getType();
303 acceptedConfigurationLine = Data(pcfgIt->getId()) + " t=" + Data(pcfgIt->getTransportId());
304 break;
305 }
306 }
307 }
308 else
309 {
310 potentialTransportType = SdpMediaLine::getTransportProtocolTypeFromString(resipMedia.protocol().c_str());
311 acceptedConfigurationLine = Data(pcfgIt->getId());
312 }
313 if (potentialTransportType == SdpMediaLine::PROTOCOL_TYPE_NONE) continue;
314
315 SdpContents::Session potentialSession(*resipSession); // create a session copy that we can modify
316
317 // Find the corresponding medium entry in the copy
318 SdpContents::Session::Medium* potentialMedium = 0;
319 std::list<SdpContents::Session::Medium>& potentialMedias = potentialSession.media();
320 std::list<SdpContents::Session::Medium>::iterator potMedIt;
321 for (potMedIt = potentialMedias.begin(); potMedIt != potentialMedias.end(); potMedIt++)
322 {
323 if (potMedIt->protocol() == resipMedia.protocol() &&
324 potMedIt->port() == (unsigned int)resipMedia.port() &&
325 potMedIt->name() == resipMedia.name())
326 {
327 potentialMedium = &(*potMedIt);
328 break;
329 }
330 }
331 resip_assert(potentialMedium);
332
333 potentialMedium->protocol() = SdpMediaLine::SdpTransportProtocolTypeString[potentialTransportType];
334
335 if (!pcfgIt->getAttributeIds().empty() || pcfgIt->getDeleteSessionAttributes() || pcfgIt->getDeleteMediaAttributes())
336 {
337 acceptedConfigurationLine += " a=";
338 if (pcfgIt->getDeleteSessionAttributes() && pcfgIt->getDeleteMediaAttributes())
339 {
340 acceptedConfigurationLine += "-ms:";
341 // TODO - need way to clear all session and media level attributes
342 }
343 else if (pcfgIt->getDeleteSessionAttributes())
344 {
345 acceptedConfigurationLine += "-s:";
346 // TODO - need way to clear all session attributes
347 }
348 else if (pcfgIt->getDeleteMediaAttributes())
349 {
350 acceptedConfigurationLine += "-m:";
351 // TODO - need way to clear all media attributes
352 }
353 }
354 bool optional = false;
355 bool first = true;
356 SdpMediaLine::SdpPotentialConfiguration::ConfigIdList::const_iterator attribIt = pcfgIt->getAttributeIds().begin();
357 for (; attribIt != pcfgIt->getAttributeIds().end(); attribIt++)
358 {
359 const SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem* configIdItem = &(*attribIt);
360
361 // Find attribute in map
362 std::map<unsigned int, std::pair<Data, Data> >::iterator acapListIt = acapList.find(configIdItem->getId());
363 if (acapListIt == acapList.end()) continue;
364 potentialMedium->addAttribute(acapListIt->second.first, acapListIt->second.second);
365
366 if (!first)
367 {
368 acceptedConfigurationLine += ",";
369 }
370 // Note: this code assumes all optional attributes are last (as specified by draft)
371 if (configIdItem->getOptional())
372 {
373 if (!optional)
374 {
375 acceptedConfigurationLine += "[";
376 optional = true;
377 }
378 }
379 acceptedConfigurationLine += Data(configIdItem->getId());
380 first = false;
381 }
382 if (optional)
383 {
384 acceptedConfigurationLine += "]";
385 }
386 SdpMediaLine* potentialSdpMediaLine = parseMediaLine(*potentialMedium, potentialSession, rtcpEnabled);
387 potentialSdpMediaLine->setPotentialMediaViewString(acceptedConfigurationLine.c_str());
388 mediaLine->addPotentialMediaView(*potentialSdpMediaLine);
389 delete potentialSdpMediaLine;
390 }
391 }
392 }
393
394 // Add the media line to the sdp
395 sdp->addMediaLine(mediaLine);
396 }
397
398 return sdp;
399}
400
401// Order in which to choose between several fingerprints (RFC 8122) - lower is preferred. SHA-256
402// is the most implemented hash type currently used for fingerprints, so prefer it over all others,
403// then the other SHA-2 functions, then SHA-1. MD5 and MD2 aren't safe to authenticate a
404// certificate with, so only take one of those if there is nothing else.
405static int
407{
408 switch(hashType)
409 {
417 default: return 7; // FINGERPRINT_HASH_FUNC_NONE
418 }
419}
420
421// Resolve a direction attribute stated directly on the session. Returns false if the
422// session states no direction at all.
423static bool
425{
426 if(resipSession.exists("sendrecv"))
427 {
429 }
430 else if(resipSession.exists("sendonly"))
431 {
433 }
434 else if(resipSession.exists("recvonly"))
435 {
437 }
438 else if(resipSession.exists("inactive"))
439 {
441 }
442 else
443 {
444 return false;
445 }
446 return true;
447}
448
449// Resolve a direction attribute stated directly on the medium, ignoring any inherited
450// from the session. Returns false if the medium states no direction of its own.
451//
452// Medium::exists() deliberately falls back to the session, so it cannot by itself tell
453// a media-level attribute from an inherited one; querying the session directly does.
454// An attribute stated on both medium and session is reported here as absent, which is
455// harmless: the session-level fallback then yields the identical direction.
456static bool
458{
459 if(resipMedia.exists("sendrecv") && !resipSession.exists("sendrecv"))
460 {
462 }
463 else if(resipMedia.exists("sendonly") && !resipSession.exists("sendonly"))
464 {
466 }
467 else if(resipMedia.exists("recvonly") && !resipSession.exists("recvonly"))
468 {
470 }
471 else if(resipMedia.exists("inactive") && !resipSession.exists("inactive"))
472 {
474 }
475 else
476 {
477 return false;
478 }
479 return true;
480}
481
483SdpHelper::parseMediaLine(const SdpContents::Session::Medium& resipMedia, const SdpContents::Session& resipSession, bool sessionRtcpEnabled)
484{
485 bool rtcpEnabledForMedia = sessionRtcpEnabled; // Default to Session setting
486 SdpMediaLine* mediaLine = new SdpMediaLine();
487
488 mediaLine->setMediaType(resipMedia.name());
489 mediaLine->setTransportProtocolType(resipMedia.protocol());
490
491 // Get PTime for media line to assign to codecs
492 unsigned int ptime=20; // default !slg! this default should be dependant on codec type - ie. G723 should be 30, etc.
493 if(resipMedia.exists("ptime"))
494 {
495 ptime = resipMedia.getValues("ptime").front().convertInt();
496 mediaLine->setPacketTime(ptime);
497 }
498
499 // Iterate Through Codecs
500 {
501 const std::list<SdpContents::Session::Codec>& codecs = resipMedia.codecs();
502 std::list<SdpContents::Session::Codec>::const_iterator it2;
503 for(it2 = codecs.begin(); it2 != codecs.end(); it2++)
504 {
505 const SdpContents::Session::Codec& resipCodec = *it2;
506
507 SdpCodec* codec = new SdpCodec(resipCodec.payloadType(),
508 resipMedia.name().c_str(),
509 resipCodec.getName().c_str(),
510 resipCodec.getRate(),
511 ptime * 1000,
512 resipCodec.encodingParameters().empty() ? 1 : resipCodec.encodingParameters().convertInt() /* Num Channels */,
513 resipCodec.parameters().c_str());
514 mediaLine->addCodec(*codec);
515 delete codec;
516 }
517 }
518
519 mediaLine->setTitle(resipMedia.information().c_str()); // i=
520
521 // Iterrate through bandwidths, b=
522 // Note: this is done before connections so that we can see if RTCP is disabled or not
523 {
524 const std::list<SdpContents::Session::Bandwidth>& bandwidths = resipMedia.bandwidths();
525 std::list<SdpContents::Session::Bandwidth>::const_iterator it;
526 bool RRSetToZero=false;
527 bool RSSetToZero=false;
528 for(it = bandwidths.begin(); it != bandwidths.end(); it++)
529 {
530 Sdp::SdpBandwidthType type = Sdp::SdpBandwidth::getTypeFromString(it->modifier().c_str());
531 if(type != Sdp::BANDWIDTH_TYPE_NONE)
532 {
533 mediaLine->addBandwidth(type, it->kbPerSecond());
534 if(type == Sdp::BANDWIDTH_TYPE_RR)
535 {
536 if(it->kbPerSecond() == 0)
537 {
538 RRSetToZero = true;
539 }
540 else
541 {
542 // Explicit settings in the media override session bandwidth settings that may have disabled rtcp
543 rtcpEnabledForMedia = true;
544 }
545 }
546 else if(type == Sdp::BANDWIDTH_TYPE_RS)
547 {
548 if(it->kbPerSecond() == 0)
549 {
550 RSSetToZero = true;
551 }
552 else
553 {
554 // Explicit settings in the media override session bandwidth settings that may have disabled rtcp
555 rtcpEnabledForMedia = true;
556 }
557 }
558 }
559 }
560 // Rtcp if considered disabled if RR and RS are both set to 0
561 if(RRSetToZero && RSSetToZero)
562 {
563 rtcpEnabledForMedia = false;
564 }
565 }
566
567 // Iterate Through Connections, c=
568 {
569 unsigned int numPorts = resipMedia.multicast() != 0 ? resipMedia.multicast() : 1; // Protect against some user error for local sdp builds where user may accidently specify 0 for multicast
570 unsigned int i=0;
571
572 // If the number of ports specified on the m= line matches the number of multicast addresses, then pair them up 1-1
573 // if there are multiple addresses and multiple ports but the numbers don't match create num addresses * num ports connections
574 // If their is only one port specified, the use it with each connection
575 // If there is only one address and multiple ports then add addtional connections for each port
576 const std::list<SdpContents::Session::Connection>& connections = resipMedia.getConnections();
577 std::list<SdpContents::Session::Connection>::const_iterator it2;
578 if(connections.size() == numPorts) // if there is a 1-1 mapping between numAddresses and numPorts, then pair them up
579 {
580 for(it2 = connections.begin(); it2 != connections.end(); it2++, i++)
581 {
582 const SdpContents::Session::Connection& resipConnection = *it2;
583
585 convertResipAddressType(resipConnection.getAddressType()),
586 resipConnection.getAddress().c_str(),
587 resipMedia.port() + (i*2),
588 resipConnection.ttl());
589 }
590 }
591 else
592 {
593 for(it2 = connections.begin(); it2 != connections.end(); it2++)
594 {
595 const SdpContents::Session::Connection& resipConnection = *it2;
596
597 for(i = 0; i < numPorts; i++)
598 {
600 convertResipAddressType(resipConnection.getAddressType()),
601 resipConnection.getAddress().c_str(),
602 resipMedia.port() + (i*2),
603 resipConnection.ttl());
604 }
605 }
606 }
607 }
608
609 // Add Rtcp connections (if enabled) - if attributes are present use them, otherwise use default rule
610 {
611 if(rtcpEnabledForMedia) // Set when iterrating through bandwidth settings
612 {
613 // Note: RFC3605 rtcp-attribute does not support multicast streams - see section 3.2 of RFC
614 if(mediaLine->getConnections().size() == 1 && resipMedia.exists("rtcp"))
615 {
616 unsigned int ipv4ttl = 0;
618
619 ParseBuffer pb(resipMedia.getValues("rtcp").front());
620 Data address;
621 unsigned int port = pb.uInt32();
622 pb.skipToChar(Symbols::SPACE[0]);
623 if(!pb.eof())
624 {
625 const char* anchor = pb.skipWhitespace();
626 if(!pb.eof())
627 {
628 pb.skipChar('I');
629 pb.skipChar('N');
630
631 anchor = pb.skipChar(Symbols::SPACE[0]);
632 pb.skipToChar(Symbols::SPACE[0]);
633 pb.data(address, anchor); // use address as temp storage
634 addrType = Sdp::getAddressTypeFromString(address.c_str());
635 anchor = pb.skipChar(Symbols::SPACE[0]);
636 pb.skipToOneOf(Symbols::SPACE, Symbols::SLASH);
637 pb.data(address, anchor);
638 if(addrType == Sdp::ADDRESS_TYPE_IP4 && !pb.eof() && *pb.position() == Symbols::SLASH[0])
639 {
640 pb.skipChar();
641 ipv4ttl = pb.integer();
642 }
643 }
644 }
645 if(address.empty()) // If connection address was not specified here - use the c= line
646 {
647 SdpMediaLine::SdpConnection *connection = (SdpMediaLine::SdpConnection*)&mediaLine->getConnections().front();
648 mediaLine->addRtcpConnection(connection->getNetType(),
649 connection->getAddressType(),
650 connection->getAddress().data(),
651 port,
652 connection->getMulticastIpV4Ttl());
653 }
654 else
655 {
656 mediaLine->addRtcpConnection(Sdp::NET_TYPE_IN, addrType, address.c_str(), port, ipv4ttl);
657 }
658 }
659 else // default rule is that rtcp is sent on all connections, by adding 1 to the port
660 {
661 // Iterrate through each connection and add a corresponding RTCP connection
662 SdpMediaLine::ConnectionList::const_iterator it2 = mediaLine->getConnections().begin();
663 for(;it2 != mediaLine->getConnections().end(); it2++)
664 {
665 mediaLine->addRtcpConnection(it2->getNetType(),
666 it2->getAddressType(),
667 it2->getAddress().data(),
668 it2->getPort() + 1,
669 it2->getMulticastIpV4Ttl());
670 }
671 }
672 }
673 }
674
675 // k=
677 {
679 }
680 else if(resipSession.getEncryption().getMethod() != SdpContents::Session::Encryption::NoEncryption) // check if set at session level
681 {
682 mediaLine->setEncryptionKey(convertResipEncryptionMethod(resipSession.getEncryption().getMethod()), resipSession.getEncryption().getKey().c_str());
683 }
684
685 // Set direction, a=sendrecv, a=sendonly, a=recvonly, a=inactive
686 //
687 // A direction stated on the medium overrides one stated at session level: RFC 4566
688 // makes a session-level attribute only a default for media sections that omit their
689 // own. Checking the medium first matters because Medium::exists() falls back to the
690 // session, so a plain if/else chain over resipMedia.exists() lets a session-level
691 // a=sendrecv shadow a media-level a=sendonly -- a pairing Firefox emits routinely.
693 if(!getMediumDirection(resipMedia, resipSession, direction) &&
694 !getSessionDirection(resipSession, direction))
695 {
696 direction = SdpMediaLine::DIRECTION_TYPE_SENDRECV; // neither states one: SDP default
697 }
698 mediaLine->setDirection(direction);
699
700 // Note ptime is set above
701 if(resipMedia.exists("maxptime"))
702 {
703 mediaLine->setMaxPacketTime(resipMedia.getValues("maxptime").front().convertUnsignedLong());
704 }
705
706 if(resipMedia.exists("orient"))
707 {
708 mediaLine->setOrientation(SdpMediaLine::getOrientationTypeFromString(resipMedia.getValues("orient").front().c_str()));
709 }
710
711 if(resipMedia.exists("sdplang"))
712 {
713 mediaLine->setDescriptionLanguage(resipMedia.getValues("sdplang").front().c_str());
714 }
715
716 if(resipMedia.exists("lang"))
717 {
718 mediaLine->setLanguage(resipMedia.getValues("lang").front().c_str());
719 }
720
721 if(resipMedia.exists("framerate"))
722 {
723 mediaLine->setFrameRate(resipMedia.getValues("framerate").front().convertUnsignedLong());
724 }
725
726 if(resipMedia.exists("quality"))
727 {
728 mediaLine->setQuality(resipMedia.getValues("quality").front().convertUnsignedLong());
729 }
730
731 if(resipMedia.exists("setup"))
732 {
733 mediaLine->setTcpSetupAttribute(SdpMediaLine::getTcpSetupAttributeFromString(resipMedia.getValues("setup").front().c_str()));
734 }
735
736 if(resipMedia.exists("connection"))
737 {
738 mediaLine->setTcpConnectionAttribute(SdpMediaLine::getTcpConnectionAttributeFromString(resipMedia.getValues("connection").front().c_str()));
739 }
740
741 if(resipMedia.exists("crypto"))
742 {
743 const std::list<Data>& cryptos = resipMedia.getValues("crypto");
744 std::list<Data>::const_iterator it2;
745 for(it2 = cryptos.begin(); it2 != cryptos.end(); it2++)
746 {
748 if(crypto)
749 {
750 mediaLine->addCryptoSettings(*crypto);
751 delete crypto;
752 }
753 }
754 }
755
756 if(resipMedia.exists("fingerprint"))
757 {
758 const std::list<Data>& fingerprints = resipMedia.getValues("fingerprint");
759 std::list<Data>::const_iterator it2;
761 resip::Data bestFingerprint;
762 for (it2 = fingerprints.begin(); it2 != fingerprints.end(); it2++)
763 {
764 if (!it2->empty())
765 {
767 resip::Data fingerprint;
768 // In the future we should support multiple fingerprints better and store a list of hash
769 // algorithms and fingerprints instead of just picking one to use.
770 if (parseFingerPrintLine(*it2, hashType, fingerprint) &&
772 {
773 bestHashType = hashType;
774 bestFingerprint = fingerprint;
775 }
776 }
777 }
779 {
780 mediaLine->setFingerPrint(bestHashType, bestFingerprint.c_str());
781 }
782 }
783
784 if(resipMedia.exists("key-mgmt"))
785 {
786 Data keymgmt = resipMedia.getValues("key-mgmt").front();
787 if(!keymgmt.empty())
788 {
789 ParseBuffer pb(keymgmt);
790 Data token;
792 const char * anchor = pb.position();
793 pb.skipToChar(Symbols::SPACE[0]);
794 pb.data(token, anchor);
797 {
798 anchor = pb.skipWhitespace();
799 pb.skipToChar(Symbols::SPACE[0]);
800 pb.data(token, anchor);
801 mediaLine->setKeyManagementProtocol(keyMgmtType, token.c_str());
802 }
803 }
804 }
805
806 if(resipMedia.exists("curr"))
807 {
808 const std::list<Data>& preconds = resipMedia.getValues("curr");
809 std::list<Data>::const_iterator it2;
810 for(it2 = preconds.begin(); it2 != preconds.end(); it2++)
811 {
812 ParseBuffer pb(*it2);
813 Data token;
817 const char * anchor = pb.position();
818 pb.skipToChar(Symbols::SPACE[0]);
819 pb.data(token, anchor);
822 {
823 anchor = pb.skipWhitespace();
824 pb.skipToChar(Symbols::SPACE[0]);
825 pb.data(token, anchor);
828 {
829 anchor = pb.skipWhitespace();
830 pb.skipToChar(Symbols::SPACE[0]);
831 pb.data(token, anchor);
833 mediaLine->addPreConditionCurrentStatus(type, status, direction);
834 }
835 }
836 }
837 }
838
839 if(resipMedia.exists("conf"))
840 {
841 const std::list<Data>& preconds = resipMedia.getValues("conf");
842 std::list<Data>::const_iterator it2;
843 for(it2 = preconds.begin(); it2 != preconds.end(); it2++)
844 {
845 ParseBuffer pb(*it2);
846 Data token;
850 const char * anchor = pb.position();
851 pb.skipToChar(Symbols::SPACE[0]);
852 pb.data(token, anchor);
855 {
856 anchor = pb.skipWhitespace();
857 pb.skipToChar(Symbols::SPACE[0]);
858 pb.data(token, anchor);
861 {
862 anchor = pb.skipWhitespace();
863 pb.skipToChar(Symbols::SPACE[0]);
864 pb.data(token, anchor);
866 mediaLine->addPreConditionConfirmStatus(type, status, direction);
867 }
868 }
869 }
870 }
871
872 if(resipMedia.exists("des"))
873 {
874 const std::list<Data>& preconds = resipMedia.getValues("des");
875 std::list<Data>::const_iterator it2;
876 for(it2 = preconds.begin(); it2 != preconds.end(); it2++)
877 {
878 ParseBuffer pb(*it2);
879 Data token;
884 const char * anchor = pb.position();
885 pb.skipToChar(Symbols::SPACE[0]);
886 pb.data(token, anchor);
889 {
890 anchor = pb.skipWhitespace();
891 pb.skipToChar(Symbols::SPACE[0]);
892 pb.data(token, anchor);
894 anchor = pb.skipWhitespace();
895 pb.skipToChar(Symbols::SPACE[0]);
896 pb.data(token, anchor);
899 {
900 anchor = pb.skipWhitespace();
901 pb.skipToChar(Symbols::SPACE[0]);
902 pb.data(token, anchor);
904 mediaLine->addPreConditionDesiredStatus(type, strength, status, direction);
905 }
906 }
907 }
908 }
909
910
911#ifndef RESIP_FIXED_POINT
912 if(resipMedia.exists("maxprate"))
913 {
914 mediaLine->setMaximumPacketRate(resipMedia.getValues("maxprate").front().convertDouble());
915 }
916#else
917 // !slg! TODO
918#endif
919
920 if(resipMedia.exists("label"))
921 {
922 mediaLine->setLabel(resipMedia.getValues("label").front().c_str());
923 }
924
925 if(resipMedia.exists("mid"))
926 {
927 mediaLine->setIdentificationTag(resipMedia.getValues("mid").front().c_str());
928 }
929
930 if(resipMedia.exists("ice-ufrag"))
931 {
932 mediaLine->setIceUserFrag(resipMedia.getValues("ice-ufrag").front().c_str());
933 }
934
935 if(resipMedia.exists("ice-pwd"))
936 {
937 mediaLine->setIcePassword(resipMedia.getValues("ice-pwd").front().c_str());
938 }
939
940 if(resipMedia.exists("remote-candidates"))
941 {
942 // multiple remote candidates are allowed on one line - we will also accept multiple remote-candidate attributes
943 const std::list<Data>& preconds = resipMedia.getValues("remote-candidates");
944 std::list<Data>::const_iterator it2;
945 for(it2 = preconds.begin(); it2 != preconds.end(); it2++)
946 {
947 ParseBuffer pb(*it2);
948 Data token;
949 unsigned int componentId;
950 unsigned int port;
951 const char * anchor;
952
953 while(!pb.eof())
954 {
955 componentId = pb.uInt32();
956 pb.skipToChar(Symbols::SPACE[0]);
957 anchor = pb.skipWhitespace();
958 pb.skipToChar(Symbols::SPACE[0]);
959 pb.data(token, anchor);
960 pb.skipWhitespace();
961 port = pb.uInt32();
962 pb.skipToChar(Symbols::SPACE[0]);
963 pb.skipWhitespace();
964 mediaLine->addRemoteCandidate(componentId, token.c_str(), port);
965 }
966 }
967 }
968
969 if(resipMedia.exists("candidate"))
970 {
971 const std::list<Data>& preconds = resipMedia.getValues("candidate");
972 std::list<Data>::const_iterator it2;
973 for(it2 = preconds.begin(); it2 != preconds.end(); it2++)
974 {
975 ParseBuffer pb(*it2);
976 Data foundation;
977 unsigned int componentId;
978 Data token;
980 uint64_t priority;
981 Data address;
982 unsigned int port;
984 Data relatedAddress;
985 unsigned int relatedPort = 0;
986
987 const char * anchor = pb.position();
988 pb.skipToChar(Symbols::SPACE[0]);
989 pb.data(foundation, anchor);
990 pb.skipWhitespace();
991 componentId = pb.uInt32();
992 pb.skipToChar(Symbols::SPACE[0]);
993 anchor = pb.skipWhitespace();
994 pb.skipToChar(Symbols::SPACE[0]);
995 pb.data(token, anchor);
998 {
999 pb.skipWhitespace();
1000 priority = pb.uInt64();
1001 pb.skipToChar(Symbols::SPACE[0]);
1002 anchor = pb.skipWhitespace();
1003 pb.skipToChar(Symbols::SPACE[0]);
1004 pb.data(address, anchor);
1005 pb.skipWhitespace();
1006 port = pb.uInt32();
1007 pb.skipToChar(Symbols::SPACE[0]);
1008 anchor = pb.skipWhitespace();
1009 if(!pb.eof())
1010 {
1011 pb.skipToChar(Symbols::SPACE[0]);
1012 pb.data(token, anchor);
1013 if(token == "typ")
1014 {
1015 anchor = pb.skipWhitespace();
1016 pb.skipToChar(Symbols::SPACE[0]);
1017 pb.data(token, anchor);
1018 candidateType = SdpCandidate::getCandidateTypeFromString(token.c_str());
1019 anchor = pb.skipWhitespace();
1020 if(!pb.eof())
1021 {
1022 pb.skipToChar(Symbols::SPACE[0]);
1023 pb.data(token, anchor);
1024 }
1025 }
1026
1027 if(!pb.eof() && token == "raddr")
1028 {
1029 anchor = pb.skipWhitespace();
1030 pb.skipToChar(Symbols::SPACE[0]);
1031 pb.data(relatedAddress, anchor);
1032 anchor = pb.skipWhitespace();
1033 if(!pb.eof())
1034 {
1035 pb.skipToChar(Symbols::SPACE[0]);
1036 pb.data(token, anchor);
1037 }
1038 }
1039
1040 if(!pb.eof() && token == "rport")
1041 {
1042 pb.skipWhitespace();
1043 relatedPort = pb.uInt32();
1044 pb.skipToChar(Symbols::SPACE[0]);
1045 anchor = pb.skipWhitespace();
1046 if(!pb.eof())
1047 {
1048 pb.skipToChar(Symbols::SPACE[0]);
1049 pb.data(token, anchor);
1050 }
1051 }
1052
1053 SdpCandidate* candidate = new SdpCandidate(foundation.c_str(), componentId, transport, priority, address.c_str(), port, candidateType, relatedAddress.c_str(), relatedPort);
1054 while(!pb.eof())
1055 {
1056 Data extAttribValue;
1057 anchor = pb.skipWhitespace();
1058 pb.skipToChar(Symbols::SPACE[0]);
1059 pb.data(extAttribValue, anchor);
1060 anchor = pb.skipWhitespace();
1061 candidate->addExtensionAttribute(token.c_str(), extAttribValue.c_str());
1062 if(!pb.eof())
1063 {
1064 pb.skipToChar(Symbols::SPACE[0]);
1065 pb.data(token, anchor);
1066 }
1067 }
1068 mediaLine->addCandidate(*candidate);
1069 delete candidate;
1070 }
1071 }
1072 }
1073 }
1074
1075 mediaLine->setRtcpMuxEnabled(resipMedia.exists("rtcp-mux"));
1076
1077 return mediaLine;
1078}
1079
1081{
1082 SdpMediaLine::SdpCrypto *crypto = 0;
1083
1084 ParseBuffer pb(cryptoLine);
1085 unsigned int tag = pb.uInt32();
1086 Data token;
1088
1090 const char * anchor = pb.skipWhitespace();
1092 pb.data(token, anchor);
1095 {
1096 crypto = new SdpMediaLine::SdpCrypto;
1097 crypto->setTag(tag);
1098 crypto->setSuite(suite);
1099 anchor = pb.skipWhitespace();
1100
1101 // Loop through KeyParams
1102 while(true)
1103 {
1105 Data keyValue;
1106 unsigned int lifetime = 0;
1107 unsigned int mkiValue = 0;
1108 unsigned int mkiLength = 0;
1109
1110 parseCryptoParams(pb, method, keyValue, lifetime, mkiValue, mkiLength);
1111 crypto->addCryptoKeyParam(method, keyValue.c_str(), lifetime, mkiValue, mkiLength);
1112
1113 if(pb.eof() || *pb.position() != ';') break;
1114 anchor = pb.skipChar();
1115 }
1116 while(!pb.eof())
1117 {
1118 anchor = pb.skipWhitespace();
1119 pb.skipToOneOf(" =");
1120 pb.data(token, anchor);
1121 if(token == "KDR")
1122 {
1123 pb.skipChar();
1124 crypto->setSrtpKdr(pb.uInt32());
1125 }
1126 else if(token == "UNENCRYPTED_SRTP")
1127 {
1128 crypto->setEncryptedSrtp(false);
1129 }
1130 else if(token == "UNENCRYPTED_SRTCP")
1131 {
1132 crypto->setEncryptedSrtcp(false);
1133 }
1134 else if(token == "UNAUTHENTICATED_SRTP")
1135 {
1136 crypto->setAuthenticatedSrtp(false);
1137 }
1138 else if(token == "FEC_ORDER")
1139 {
1140 anchor = pb.skipChar();
1142 pb.data(token, anchor);
1144 }
1145 else if(token == "FEC_KEY")
1146 {
1147 anchor = pb.skipChar();
1149 Data keyValue;
1150 unsigned int lifetime = 0;
1151 unsigned int mkiValue = 0;
1152 unsigned int mkiLength = 0;
1153
1154 parseCryptoParams(pb, method, keyValue, lifetime, mkiValue, mkiLength);
1155 crypto->setSrtpFecKey(method, keyValue.c_str(), lifetime, mkiValue, mkiLength);
1156 }
1157 else if(token == "WSH")
1158 {
1159 pb.skipChar();
1160 crypto->setSrtpWsh(pb.uInt32());
1161 }
1162 else
1163 {
1164 if(!pb.eof() && *pb.position() == '=')
1165 {
1167 pb.data(token, anchor);
1168 }
1169 crypto->addGenericSessionParam(token.c_str());
1170 }
1171 }
1172 }
1173 return crypto;
1174}
1175
1177{
1178 ParseBuffer pb(fingerprintLine);
1179 pb.skipWhitespace(); // not technically allowed in the grammar but some implementations add whitespace before the hash function
1180 const char* anchor = pb.position();
1182 pb.data(fingerPrint, anchor); // just used fingerprint data temporarily
1185 {
1186 anchor = pb.skipWhitespace();
1188 pb.data(fingerPrint, anchor);
1189 return true;
1190 }
1191 return false;
1192}
1193
1194bool SdpHelper::parseTransportCapabilitiesLine(const resip::Data& tcapLine, std::list<SdpMediaLine::SdpTransportProtocolCapabilities>& tcapList)
1195{
1196 ParseBuffer pb(tcapLine);
1197 unsigned int baseTcapId = pb.uInt32();
1198 Data token;
1199 bool ok = false;
1201 while(true)
1202 {
1203 const char * anchor = pb.skipWhitespace();
1204 if(pb.eof()) break;
1206 pb.data(token, anchor);
1208 baseTcapId++;
1209 ok = true;
1210 }
1211 return ok;
1212}
1213
1214bool SdpHelper::parsePotentialConfigurationLine(const resip::Data& pcfgLine, std::list<SdpMediaLine::SdpPotentialConfiguration>& pcfgList)
1215{
1216 std::list<std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem> > attributeLists;
1217 std::list<unsigned int> transportList;
1218 bool deleteMediaAttributes = false;
1219 bool deleteSessionAttributes = false;
1220
1221 ParseBuffer pb(pcfgLine);
1222 unsigned int pcfgId = pb.uInt32();
1223 Data token;
1224 bool ok = false;
1225 bool attributesFirst = false;
1227
1228 while(!pb.eof())
1229 {
1230 const char * anchor = pb.skipWhitespace();
1231 bool optionalOn = false;
1233 if(!pb.eof())
1234 {
1235 pb.data(token, anchor);
1236 if(token == "a")
1237 {
1238 std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem> attributeList;
1239 if(transportList.empty())
1240 {
1241 attributesFirst = true;
1242 }
1243 pb.skipChar(); // skip =
1244 if(pb.eof()) break;
1245 if(*pb.position() == '-')
1246 {
1247 // We have "delete" attributes
1248 anchor = pb.skipChar();
1250 pb.data(token, anchor);
1251 if(token == "m")
1252 {
1253 deleteMediaAttributes = true;
1254 }
1255 else if(token == "s")
1256 {
1257 deleteSessionAttributes = true;
1258 }
1259 else if(token == "ms")
1260 {
1261 deleteMediaAttributes = true;
1262 deleteSessionAttributes = true;
1263 }
1264 if(!pb.eof()) pb.skipChar();
1265 }
1266 while(!pb.eof())
1267 {
1268 anchor = pb.position();
1269 pb.skipToOneOf(" ,|[]");
1270 if(pb.eof() || *pb.position() == ',' || *pb.position() == ' ')
1271 {
1272 pb.data(token, anchor);
1273 attributeList.push_back(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(token.convertUnsignedLong(), optionalOn));
1274 if(!pb.eof()) pb.skipChar();
1275 }
1276 else if(*pb.position() == '|')
1277 {
1278 pb.data(token, anchor);
1279 attributeList.push_back(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(token.convertUnsignedLong(), optionalOn));
1280 attributeLists.push_back(attributeList);
1281 attributeList.clear(); // Start a new list
1282 pb.skipChar();
1283 }
1284 else if(*pb.position() == '[')
1285 {
1286 optionalOn = true;
1287 pb.skipChar();
1288 }
1289 else if(*pb.position() == ']')
1290 {
1291 pb.data(token, anchor);
1292 attributeList.push_back(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(token.convertUnsignedLong(), optionalOn));
1293 optionalOn = false;
1294 pb.skipChar();
1295 }
1296 if(pb.eof() || *pb.position() == ' ')
1297 {
1298 attributeLists.push_back(attributeList);
1299 break;
1300 }
1301 }
1302 }
1303 else if(token == "t")
1304 {
1305 anchor = pb.skipChar();
1306 while(!pb.eof())
1307 {
1308 pb.skipToOneOf(" |");
1309 pb.data(token, anchor);
1310 transportList.push_back(token.convertUnsignedLong());
1311 if(pb.eof() || *pb.position() == ' ') break;
1312 anchor = pb.skipChar();
1313 }
1314 }
1315 else
1316 {
1317 // Mostly like an extension list - we do not support this yet - so just skip it
1319 }
1320 }
1321 }
1322
1323 // Ok we've parse everything now - build all of the potential configs
1324 if(attributesFirst)
1325 {
1326 // iterate through each attribute, then each transport
1327 std::list<std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem> >::iterator listsIt = attributeLists.begin();
1328 for(;listsIt != attributeLists.end(); listsIt++)
1329 {
1330 if(transportList.empty())
1331 {
1332 SdpMediaLine::SdpPotentialConfiguration potentialConfiguration(pcfgId, deleteMediaAttributes, deleteSessionAttributes, 0 /* no transportId */);
1333 std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem>::iterator attributesIt = listsIt->begin();
1334 for(;attributesIt != listsIt->end(); attributesIt++)
1335 {
1336 potentialConfiguration.addAttributeId(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(*attributesIt));
1337 }
1338 pcfgList.push_back(potentialConfiguration);
1339 }
1340 else
1341 {
1342 std::list<unsigned int>::iterator transportsIt = transportList.begin();
1343 for(;transportsIt != transportList.end(); transportsIt++)
1344 {
1345 SdpMediaLine::SdpPotentialConfiguration potentialConfiguration(pcfgId, deleteMediaAttributes, deleteSessionAttributes, *transportsIt);
1346 std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem>::iterator attributesIt = listsIt->begin();
1347 for(;attributesIt != listsIt->end(); attributesIt++)
1348 {
1349 potentialConfiguration.addAttributeId(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(*attributesIt));
1350 }
1351 pcfgList.push_back(potentialConfiguration);
1352 }
1353 }
1354 }
1355 }
1356 else // transports were listed first - build list in different order
1357 {
1358 std::list<unsigned int>::iterator transportsIt = transportList.begin();
1359 for(;transportsIt != transportList.end(); transportsIt++)
1360 {
1361 if(attributeLists.empty())
1362 {
1363 pcfgList.push_back(SdpMediaLine::SdpPotentialConfiguration(pcfgId, deleteMediaAttributes, deleteSessionAttributes, *transportsIt));
1364 }
1365 else
1366 {
1367 // iterate through each attribute list
1368 std::list<std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem> >::iterator listsIt = attributeLists.begin();
1369 for(;listsIt != attributeLists.end(); listsIt++)
1370 {
1371 SdpMediaLine::SdpPotentialConfiguration potentialConfiguration(pcfgId, deleteMediaAttributes, deleteSessionAttributes, *transportsIt);
1372 std::list<SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem>::iterator attributesIt = listsIt->begin();
1373 for(;attributesIt != listsIt->end(); attributesIt++)
1374 {
1375 potentialConfiguration.addAttributeId(SdpMediaLine::SdpPotentialConfiguration::ConfigIdItem(*attributesIt));
1376 }
1377 pcfgList.push_back(potentialConfiguration);
1378 }
1379 }
1380 }
1381 }
1382 return ok;
1383}
1384
1385using namespace std;
1387{
1388 std::list<SdpMediaLine::SdpTransportProtocolCapabilities> tcapList;
1389 std::list<SdpMediaLine::SdpPotentialConfiguration> pcfgList;
1390 Data tcap("1 UDP/TLS/RTP/AVP RTP/AVP");
1391 Data pcfg("1 a=-m:1,2,3,[4,5]|[6,7] x=blah t=1|2 y=foo");
1394
1395 cout << "Transport List: " << tcap << endl;
1396 std::list<SdpMediaLine::SdpTransportProtocolCapabilities>::iterator it = tcapList.begin();
1397 for(;it != tcapList.end(); it++)
1398 {
1399 cout << " Tranpsort Id=" << it->getId() << " protocolType=" << it->getType() << endl;
1400 }
1401
1402 cout << "Potential Configuration List: " << pcfg << endl;
1403 std::list<SdpMediaLine::SdpPotentialConfiguration>::iterator it2 = pcfgList.begin();
1404 for(;it2 != pcfgList.end(); it2++)
1405 {
1406 cout << " Config Id=" << it2->getId() << " deleteMediaAttr=" << it2->getDeleteMediaAttributes() << " deleteSessionAttr=" << it2->getDeleteSessionAttributes() << " transportId=" << it2->getTransportId() << endl;
1407 SdpMediaLine::SdpPotentialConfiguration::ConfigIdList::const_iterator it3 = it2->getAttributeIds().begin();
1408 for(;it3 != it2->getAttributeIds().end(); it3++)
1409 {
1410 cout << " AttributeId=" << it3->getId() << " optional=" << it3->getOptional() << endl;
1411 }
1412 }
1413
1414 return;
1415}
1416
1417void SdpHelper::parseCryptoParams(ParseBuffer& pb,
1419 Data& keyValue,
1420 unsigned int& srtpLifetime,
1421 unsigned int& srtpMkiValue,
1422 unsigned int& srtpMkiLength)
1423{
1424 const char * anchor = pb.position();
1425 Data token;
1427 pb.data(token, anchor);
1430 {
1431 anchor = pb.skipChar();
1432 pb.skipToOneOf("|;", Symbols::SPACE);
1433 pb.data(keyValue, anchor);
1434 if(!pb.eof() && *pb.position() == '|')
1435 {
1436 pb.skipChar();
1437 unsigned int base = pb.uInt32();
1438 pb.skipToOneOf("^|:;", Symbols::SPACE);
1439 if(*pb.position() == '^')
1440 {
1441 pb.skipChar();
1442 unsigned int exponent = pb.uInt32();
1443 srtpLifetime = base;
1444 while(0 != --exponent) srtpLifetime *= base;
1445 pb.skipToOneOf("|;", Symbols::SPACE);
1446 if(!pb.eof() && *pb.position() == '|')
1447 {
1448 pb.skipChar();
1449 base = pb.uInt32();
1450 pb.skipToOneOf(":;", Symbols::SPACE);
1451 }
1452 }
1453 else if(*pb.position() != ':')
1454 {
1455 srtpLifetime = base;
1456 if(!pb.eof())
1457 {
1458 if(*pb.position() == '|')
1459 {
1460 pb.skipChar();
1461 base = pb.uInt32();
1462 }
1463 pb.skipToOneOf(":;", Symbols::SPACE);
1464 }
1465 }
1466 if(!pb.eof() && *pb.position() == ':')
1467 {
1468 srtpMkiValue = base;
1469 pb.skipChar();
1470 srtpMkiLength = pb.uInt32();
1471 pb.skipToOneOf(";", Symbols::SPACE);
1472 }
1473 }
1474 }
1475 else
1476 {
1477 anchor = pb.skipChar();
1479 pb.data(keyValue, anchor);
1480 if(!pb.eof())
1481 {
1482 pb.skipToOneOf(";", Symbols::SPACE);
1483 }
1484 }
1485}
1486
1487
1488/* ====================================================================
1489
1490 Copyright (c) 2026, SIP Spectrum, Inc. https://www.sipspectrum.com
1491 Copyright (c) 2007-2008, Plantronics, Inc.
1492 All rights reserved.
1493
1494 Redistribution and use in source and binary forms, with or without
1495 modification, are permitted provided that the following conditions are
1496 met:
1497
1498 1. Redistributions of source code must retain the above copyright
1499 notice, this list of conditions and the following disclaimer.
1500
1501 2. Redistributions in binary form must reproduce the above copyright
1502 notice, this list of conditions and the following disclaimer in the
1503 documentation and/or other materials provided with the distribution.
1504
1505 3. Neither the name of Plantronics nor the names of its contributors
1506 may be used to endorse or promote products derived from this
1507 software without specific prior written permission.
1508
1509 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1510 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1511 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1512 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1513 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1514 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1515 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1516 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1517 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1518 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1519 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1520
1521 ==================================================================== */
#define resip_assert(x)
This file needs to work for both C and C++ code.
static int fingerPrintHashFuncPreference(SdpMediaLine::SdpFingerPrintHashFuncType hashType)
static bool getMediumDirection(const SdpContents::Session::Medium &resipMedia, const SdpContents::Session &resipSession, SdpMediaLine::SdpDirectionType &direction)
static bool getSessionDirection(const SdpContents::Session &resipSession, SdpMediaLine::SdpDirectionType &direction)
void testSDPCapabilityNegotiationParsing(void)
static sdpcontainer::SdpMediaLine::SdpEncryptionMethod convertResipEncryptionMethod(resip::SdpContents::Session::Encryption::KeyType resipMethod)
Definition SdpHelper.cxx:20
static bool parsePotentialConfigurationLine(const resip::Data &pcfgLine, std::list< sdpcontainer::SdpMediaLine::SdpPotentialConfiguration > &pcfgList)
static sdpcontainer::Sdp::SdpAddressType convertResipAddressType(resip::SdpContents::AddrType resipAddrType)
Definition SdpHelper.cxx:15
static bool parseTransportCapabilitiesLine(const resip::Data &tcapLine, std::list< sdpcontainer::SdpMediaLine::SdpTransportProtocolCapabilities > &tcapList)
static bool parseFingerPrintLine(const resip::Data &fingerprintLine, sdpcontainer::SdpMediaLine::SdpFingerPrintHashFuncType &hashType, resip::Data &fingerPrint)
static sdpcontainer::Sdp * createSdpFromResipSdp(const resip::SdpContents &resipSdp)
Definition SdpHelper.cxx:37
static sdpcontainer::SdpMediaLine::SdpCrypto * parseCryptoLine(const resip::Data &cryptoLine)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
const char * begin() const noexcept
Returns a pointer to the beginning of the buffer used by the Data.
Definition Data.hxx:642
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Provides string-parsing functionality with protection from buffer overflow.
uint32_t uInt32()
dcm! – merge these, ask about length checks
CurrentPosition skipToEnd()
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
parameters for a specific codec are stored in this class.
const Data & encodingParameters() const
returns the encoding parameters associated with this codec
const Data & getName() const
returns the name of the codec.
int payloadType() const
returns the RTP payload type associated with this codec.
int getRate() const
returns the name of the codec.
Process c= (connection) lines in SDP.
const Data & getAddress() const
returns the connection address
AddrType getAddressType() const
returns the connection address type
process m= (media announcement) blocks
const std::list< Connection > getConnections() const
get a list of Connection objects, including the Session's c= line.
void addAttribute(const Data &key, const Data &value=Data::Empty)
add a media attribute line
const std::list< Data > & getValues(const Data &key) const
get the attribute values corresponding to the key - returns the attributes set on this medium,...
bool exists(const Data &key) const
tests if an a= key is present in the media section
int port() const
return the base port
std::list< Data > getMergedValues(const Data &key) const
get the attribute values corresponding to the key - returns both the attributes set on this medium,...
const CodecContainer & codecs() const
preferred codec/format interface
const Encryption & getEncryption() const
const std::list< Bandwidth > & bandwidths() const
get a list of bandwidth lines
int multicast() const
get the number of transport port pairs
const Data & information() const
get optional i= (information) line contents
const Data & protocol() const
return the transport protocol
const Data & name() const
return the media type
const uint64_t & getVersion() const
returns the session version
const Data & getAddress() const
returns the session address type
const uint64_t & getSessionId() const
returns the session ID
const Data & user() const
returns the user string for the session
AddrType getAddressType() const
returns the session address type
const std::list< Adjustment > & getAdjustments() const
Provides an interface to read and modify SDP bodies.
const std::list< Bandwidth > & bandwidths() const
return session Bandwidth lines
const std::list< Time > & getTimes() const
return session Time lines
const Timezones & getTimezones() const
const std::list< Phone > & getPhones() const
return session Phone number list
const Data & information() const
return session Information
const std::list< Email > & getEmails() const
return session Email list
int version() const
return session version
const Encryption & getEncryption() const
const Origin & origin() const
return session Origin line
const std::list< Data > & getValues(const Data &key) const
get the attribute values corresponding to the key
const Data & name() const
return session name
bool exists(const Data &key) const
tests if an a= key is present in the session
const MediumContainer & media() const
return session Media lines
const Uri & uri() const
return session Uri
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
Session & session()
get the parsed SDP
static const char * SPACE
Definition Symbols.hxx:34
static const char * COLON
Definition Symbols.hxx:15
static const char * SLASH
Definition Symbols.hxx:32
static const char * EQUALS
Definition Symbols.hxx:29
Data & host()
Definition Uri.hxx:40
void addExtensionAttribute(const char *name, const char *value)
static SdpCandidateType getCandidateTypeFromString(const char *type)
static SdpCandidateTransportType getCandidateTransportTypeFromString(const char *type)
const resip::Data & getAddress() const
Sdp::SdpAddressType getAddressType() const
void setSrtpKdr(unsigned int srtpKdr)
void setSrtpWsh(unsigned int srtpWsh)
void setSuite(SdpCryptoSuiteType suite)
void addCryptoKeyParam(SdpCryptoKeyMethod keyMethod, const char *keyValue, unsigned int srtpLifetime=0, unsigned int srtpMkiValue=0, unsigned int srtpMkiLength=0)
void setEncryptedSrtcp(bool encryptedSrtcp)
void setSrtpFecKey(SdpCryptoKeyMethod keyMethod, const char *keyValue, unsigned int srtpLifetime=0, unsigned int srtpMkiValue=0, unsigned int srtpMkiLength=0)
static SdpCryptoSrtpFecOrderType getSrtpFecOrderFromString(const char *order)
void addGenericSessionParam(const char *sessionParam)
void setEncryptedSrtp(bool encryptedSrtp)
void setAuthenticatedSrtp(bool authenticatedSrtp)
void setSrtpFecOrder(SdpCryptoSrtpFecOrderType srtpFecOrder)
void addAttributeId(unsigned int id, bool optional)
static SdpCryptoSuiteType getCryptoSuiteTypeFromString(const char *type)
static SdpTcpSetupAttribute getTcpSetupAttributeFromString(const char *attrib)
void addCodec(const SdpCodec &codec)
void setRtcpMuxEnabled(bool enabled)
void setMaximumPacketRate(double maximumPacketRate)
void setLabel(const char *label)
static SdpPreConditionStatusType getPreConditionStatusTypeFromString(const char *type)
void setTitle(const char *title)
SdpTransportProtocolType
Transport protocol identifiers for the SDP "m=" line (proto field).
static SdpKeyManagementProtocolType getKeyManagementProtocolTypeFromString(const char *type)
void addCryptoSettings(const SdpCrypto &crypto)
static SdpCryptoKeyMethod getCryptoKeyMethodFromString(const char *type)
void setIdentificationTag(const char *identificationTag)
static SdpTransportProtocolType getTransportProtocolTypeFromString(const char *type)
void addRtcpConnection(Sdp::SdpNetType netType, Sdp::SdpAddressType addressType, const char *address, unsigned int port, unsigned int multicastIpV4Ttl=0)
void setPacketTime(unsigned int packetTime)
static SdpPreConditionType getPreConditionTypeFromString(const char *type)
void setOrientation(SdpOrientationType orientation)
void setFrameRate(unsigned int frameRate)
static SdpOrientationType getOrientationTypeFromString(const char *type)
void addRemoteCandidate(unsigned int componentId, const char *connectionAddress, unsigned int port)
void addBandwidth(Sdp::SdpBandwidthType type, unsigned int bandwidth)
void addPreConditionDesiredStatus(SdpPreConditionType type, SdpPreConditionStrengthType strength, SdpPreConditionStatusType status, SdpPreConditionDirectionType direction)
void setQuality(unsigned int quality)
static SdpFingerPrintHashFuncType getFingerPrintHashFuncTypeFromString(const char *type)
static SdpPreConditionDirectionType getPreConditionDirectionTypeFromString(const char *type)
void addConnection(Sdp::SdpNetType netType, Sdp::SdpAddressType addressType, const char *address, unsigned int port, unsigned int multicastIpV4Ttl=0)
void setDescriptionLanguage(const char *descriptionLanguage)
void setLanguage(const char *language)
void setKeyManagementProtocol(SdpKeyManagementProtocolType protocol, const char *data)
void setTcpSetupAttribute(SdpTcpSetupAttribute tcpSetupAttribute)
void setTcpConnectionAttribute(SdpTcpConnectionAttribute tcpConnectionAttribute)
void setDirection(SdpDirectionType direction)
static SdpTcpConnectionAttribute getTcpConnectionAttributeFromString(const char *attrib)
void addPreConditionConfirmStatus(SdpPreConditionType type, SdpPreConditionStatusType status, SdpPreConditionDirectionType direction)
void setIceUserFrag(const char *iceUserFrag)
void setMaxPacketTime(unsigned int maxPacketTime)
void setPotentialMediaViewString(const char *potentialMediaViewString)
void addPotentialMediaView(const SdpMediaLine &potentialMediaView)
void setTransportProtocolType(SdpTransportProtocolType transportProtocolType)
void addCandidate(SdpCandidate &candidate)
static SdpPreConditionStrengthType getPreConditionStrengthTypeFromString(const char *type)
static const char * SdpTransportProtocolTypeString[]
void setEncryptionKey(SdpEncryptionMethod method, const char *key)
void addPreConditionCurrentStatus(SdpPreConditionType type, SdpPreConditionStatusType status, SdpPreConditionDirectionType direction)
void setFingerPrint(SdpFingerPrintHashFuncType fingerPrintHashFunction, const char *fingerPrint)
void setIcePassword(const char *icePassword)
void setMediaType(SdpMediaType mediaType)
const ConnectionList & getConnections() const
static SdpBandwidthType getTypeFromString(const char *type)
Definition Sdp.cxx:142
void addIdentificationTag(const char *identificationTag)
Definition Sdp.hxx:169
static SdpGroupSemantics getSemanticsFromString(const char *type)
Definition Sdp.cxx:200
void addOffsetFromStartTime(unsigned int offset)
Definition Sdp.hxx:89
void addRepeat(const SdpTimeRepeat &sdpTimeRepeat)
Definition Sdp.hxx:110
void setSessionLanguage(const char *sessionLanguage)
Definition Sdp.hxx:244
void addEmailAddress(const char *emailAddress)
Definition Sdp.hxx:216
void setConferenceType(SdpConferenceType conferenceType)
Definition Sdp.hxx:237
void setMaximumPacketRate(double maximumPacketRate)
Definition Sdp.hxx:246
static SdpConferenceType getConferenceTypeFromString(const char *type)
Definition Sdp.cxx:173
void setSessionUri(const char *sessionUri)
Definition Sdp.hxx:214
void setSessionName(const char *sessionName)
Definition Sdp.hxx:212
void addTimeZone(int adjustmentTime, int offset)
Definition Sdp.hxx:230
void setIcePassiveOnlyMode(bool icePassiveOnlyMode)
Definition Sdp.hxx:239
void setToolNameAndVersion(const char *toolNameAndVersion)
Definition Sdp.hxx:236
void setCharSet(const char *charSet)
Definition Sdp.hxx:238
static SdpAddressType getAddressTypeFromString(const char *type)
Definition Sdp.cxx:123
void addMediaLine(SdpMediaLine *mediaLine)
Definition Sdp.cxx:243
void addGroup(const SdpGroup &group)
Definition Sdp.hxx:241
void addPhoneNumber(const char *phoneNumber)
Definition Sdp.hxx:219
void addBandwidth(SdpBandwidthType type, unsigned int bandwidth)
Definition Sdp.hxx:222
void setSdpVersion(unsigned int sdpVersion)
Definition Sdp.hxx:202
void setKeywords(const char *keywords)
Definition Sdp.hxx:235
void setSessionInformation(const char *sessionInformation)
Definition Sdp.hxx:213
@ BANDWIDTH_TYPE_NONE
Definition Sdp.hxx:42
void addTime(uint64_t startTime, uint64_t stopTime)
Definition Sdp.hxx:226
void setOriginatorInfo(const char *userName, uint64_t sessionId, uint64_t sessionVersion, SdpNetType netType, SdpAddressType addressType, const char *unicastAddress)
Definition Sdp.cxx:227
void setDescriptionLanguage(const char *descriptionLanguage)
Definition Sdp.hxx:245
void setCategory(const char *category)
Definition Sdp.hxx:234
dcm! – add UnusedChecking(_enum) below;
unsigned __int64 uint64_t
Definition stdint.h:95