bool SipccSdpAttributeList::LoadGroups(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { uint16_t attrCount = 0; if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_GROUP, &attrCount) != SDP_SUCCESS) { MOZ_ASSERT(false, "Could not get count of group attributes"); errorHolder.AddParseError(0, "Could not get count of group attributes"); return false; } UniquePtr<SdpGroupAttributeList> groups = MakeUnique<SdpGroupAttributeList>(); for (uint16_t attr = 1; attr <= attrCount; ++attr) { SdpGroupAttributeList::Semantics semantics; std::vector<std::string> tags; switch (sdp_get_group_attr(sdp, level, 0, attr)) { case SDP_GROUP_ATTR_FID: semantics = SdpGroupAttributeList::kFid; break; case SDP_GROUP_ATTR_LS: semantics = SdpGroupAttributeList::kLs; break; case SDP_GROUP_ATTR_ANAT: semantics = SdpGroupAttributeList::kAnat; break; case SDP_GROUP_ATTR_BUNDLE: semantics = SdpGroupAttributeList::kBundle; break; default: continue; } uint16_t idCount = sdp_get_group_num_id(sdp, level, 0, attr); for (uint16_t id = 1; id <= idCount; ++id) { const char* idStr = sdp_get_group_id(sdp, level, 0, attr, id); if (!idStr) { std::ostringstream os; os << "bad a=group identifier at " << (attr - 1) << ", " << (id - 1); errorHolder.AddParseError(0, os.str()); return false; } tags.push_back(std::string(idStr)); } groups->PushEntry(semantics, tags); } if (!groups->mGroups.empty()) { SetAttribute(groups.release()); } return true; }
nsresult SdpHelper::AddCandidateToSdp(Sdp* sdp, const std::string& candidateUntrimmed, const std::string& mid, uint16_t level) { if (level >= sdp->GetMediaSectionCount()) { SDP_SET_ERROR("Index " << level << " out of range"); return NS_ERROR_INVALID_ARG; } // Trim off '[a=]candidate:' size_t begin = candidateUntrimmed.find(':'); if (begin == std::string::npos) { SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")"); return NS_ERROR_INVALID_ARG; } ++begin; std::string candidate = candidateUntrimmed.substr(begin); // TODO(bug 1095793): mid SdpMediaSection& msection = sdp->GetMediaSection(level); SdpAttributeList& attrList = msection.GetAttributeList(); UniquePtr<SdpMultiStringAttribute> candidates; if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) { // Create new candidates.reset( new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute)); } else { // Copy existing candidates.reset(new SdpMultiStringAttribute( *static_cast<const SdpMultiStringAttribute*>( attrList.GetAttribute(SdpAttribute::kCandidateAttribute)))); } candidates->PushEntry(candidate); attrList.SetAttribute(candidates.release()); return NS_OK; }
bool SipccSdpAttributeList::LoadFingerprint(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { char* value; UniquePtr<SdpFingerprintAttributeList> fingerprintAttrs; for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_result_e result = sdp_attr_get_dtls_fingerprint_attribute( sdp, level, 0, SDP_ATTR_DTLS_FINGERPRINT, i, &value); if (result != SDP_SUCCESS) { break; } std::string fingerprintAttr(value); uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_DTLS_FINGERPRINT, level, 0, i); // sipcc does not expose parse code for this size_t start = fingerprintAttr.find_first_not_of(" \t"); if (start == std::string::npos) { errorHolder.AddParseError(lineNumber, "Empty fingerprint attribute"); return false; } size_t end = fingerprintAttr.find_first_of(" \t", start); if (end == std::string::npos) { // One token, no trailing ws errorHolder.AddParseError(lineNumber, "Only one token in fingerprint attribute"); return false; } std::string algorithmToken(fingerprintAttr.substr(start, end - start)); start = fingerprintAttr.find_first_not_of(" \t", end); if (start == std::string::npos) { // One token, trailing ws errorHolder.AddParseError(lineNumber, "Only one token in fingerprint attribute"); return false; } std::string fingerprintToken(fingerprintAttr.substr(start)); std::vector<uint8_t> fingerprint = SdpFingerprintAttributeList::ParseFingerprint(fingerprintToken); if (fingerprint.size() == 0) { errorHolder.AddParseError(lineNumber, "Malformed fingerprint token"); return false; } if (!fingerprintAttrs) { fingerprintAttrs.reset(new SdpFingerprintAttributeList); } // Don't assert on unknown algorithm, just skip fingerprintAttrs->PushEntry(algorithmToken, fingerprint, false); } if (fingerprintAttrs) { SetAttribute(fingerprintAttrs.release()); } return true; }
nsresult SdpHelper::AddCandidateToSdp(Sdp* sdp, const std::string& candidateUntrimmed, const std::string& mid, uint16_t level) { if (level >= sdp->GetMediaSectionCount()) { SDP_SET_ERROR("Index " << level << " out of range"); return NS_ERROR_INVALID_ARG; } // Trim off '[a=]candidate:' size_t begin = candidateUntrimmed.find(':'); if (begin == std::string::npos) { SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")"); return NS_ERROR_INVALID_ARG; } ++begin; std::string candidate = candidateUntrimmed.substr(begin); // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-11#section-3.4.2.1 // Implementations receiving an ICE Candidate object MUST use the MID if // present, or the m= line index, if not (as it could have come from a // non-JSEP endpoint). (bug 1095793) SdpMediaSection* msection = 0; if (!mid.empty()) { // FindMsectionByMid could return nullptr msection = FindMsectionByMid(*sdp, mid); // Check to make sure mid matches what we'd get by // looking up the m= line using the level. (mjf) std::string checkMid; nsresult rv = GetMidFromLevel(*sdp, level, &checkMid); if (NS_FAILED(rv)) { return rv; } if (mid != checkMid) { SDP_SET_ERROR("Mismatch between mid and level - \"" << mid << "\" is not the mid for level " << level << "; \"" << checkMid << "\" is"); return NS_ERROR_INVALID_ARG; } } if (!msection) { msection = &(sdp->GetMediaSection(level)); } SdpAttributeList& attrList = msection->GetAttributeList(); UniquePtr<SdpMultiStringAttribute> candidates; if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) { // Create new candidates.reset( new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute)); } else { // Copy existing candidates.reset(new SdpMultiStringAttribute( *static_cast<const SdpMultiStringAttribute*>( attrList.GetAttribute(SdpAttribute::kCandidateAttribute)))); } candidates->PushEntry(candidate); attrList.SetAttribute(candidates.release()); return NS_OK; }