📄 sdpcontents.cxx
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
#include "resip/stack/SdpContents.hxx"
#include "rutil/ParseBuffer.hxx"
#include "rutil/DataStream.hxx"
#include "resip/stack/Symbols.hxx"
#include "rutil/Logger.hxx"
#include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::SDP
using namespace resip;
using namespace std;
const SdpContents SdpContents::Empty;
bool
SdpContents::init()
{
static ContentsFactory<SdpContents> factory;
(void)factory;
return true;
}
const char* NetworkType[] = {"???", "IP4", "IP6"};
static const Data rtpmap("rtpmap");
static const Data fmtp("fmtp");
// RFC2327 6. page 9
// "parsers should be tolerant and accept records terminated with a single
// newline character"
void skipEol(ParseBuffer& pb)
{
while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
*pb.position() == Symbols::TAB[0]))
{
pb.skipChar();
}
if (*pb.position() == Symbols::LF[0])
{
pb.skipChar();
}
else
{
// allow extra 0x0d bytes.
while(*pb.position() == Symbols::CR[0])
{
pb.skipChar();
}
pb.skipChar(Symbols::LF[0]);
}
}
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
: mAttributes(rhs.mAttributes)
{
}
AttributeHelper::AttributeHelper()
{
}
AttributeHelper&
AttributeHelper::operator=(const AttributeHelper& rhs)
{
if (this != &rhs)
{
mAttributes = rhs.mAttributes;
}
return *this;
}
bool
AttributeHelper::exists(const Data& key) const
{
return mAttributes.find(key) != mAttributes.end();
}
const list<Data>&
AttributeHelper::getValues(const Data& key) const
{
if (!exists(key))
{
static const list<Data> emptyList;
return emptyList;
}
return mAttributes.find(key)->second;
}
ostream&
AttributeHelper::encode(ostream& s) const
{
for (HashMap< Data, list<Data> >::const_iterator i = mAttributes.begin();
i != mAttributes.end(); ++i)
{
for (list<Data>::const_iterator j = i->second.begin();
j != i->second.end(); ++j)
{
s << "a="
<< i->first;
if (!j->empty())
{
s << Symbols::COLON[0] << *j;
}
s << Symbols::CRLF;
}
}
return s;
}
void
AttributeHelper::parse(ParseBuffer& pb)
{
while (!pb.eof() && *pb.position() == 'a')
{
Data key;
Data value;
pb.skipChar('a');
const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
pb.data(key, anchor);
if (!pb.eof() && *pb.position() == Symbols::COLON[0])
{
anchor = pb.skipChar(Symbols::COLON[0]);
pb.skipToOneOf(Symbols::CRLF);
pb.data(value, anchor);
}
if(!pb.eof()) skipEol(pb);
mAttributes[key].push_back(value);
}
}
void
AttributeHelper::addAttribute(const Data& key, const Data& value)
{
mAttributes[key].push_back(value);
}
void
AttributeHelper::clearAttribute(const Data& key)
{
mAttributes.erase(key);
}
SdpContents::SdpContents() : Contents(getStaticType())
{
}
SdpContents::SdpContents(HeaderFieldValue* hfv, const Mime& contentTypes)
: Contents(hfv, contentTypes)
{
}
SdpContents::SdpContents(const SdpContents& rhs)
: Contents(rhs),
mSession(rhs.mSession)
{
}
SdpContents::~SdpContents()
{
}
SdpContents&
SdpContents::operator=(const SdpContents& rhs)
{
if (this != &rhs)
{
Contents::operator=(rhs);
mSession = rhs.mSession;
}
return *this;
}
Contents*
SdpContents::clone() const
{
return new SdpContents(*this);
}
Data
SdpContents::getBodyData() const
{
checkParsed();
Data d;
{
DataStream s(d);
mSession.encode(s);
}
return d;
}
void
SdpContents::parse(ParseBuffer& pb)
{
mSession.parse(pb);
}
ostream&
SdpContents::encodeParsed(ostream& s) const
{
mSession.encode(s);
return s;
}
const Mime&
SdpContents::getStaticType()
{
static Mime type("application", "sdp");
return type;
}
static Data nullOrigin("0.0.0.0");
SdpContents::Session::Origin::Origin()
: mUser(Data::Empty),
mSessionId(0),
mVersion(0),
mAddrType(IP4),
mAddress(nullOrigin)
{}
SdpContents::Session::Origin::Origin(const Origin& rhs)
: mUser(rhs.mUser),
mSessionId(rhs.mSessionId),
mVersion(rhs.mVersion),
mAddrType(rhs.mAddrType),
mAddress(rhs.mAddress)
{
}
SdpContents::Session::Origin&
SdpContents::Session::Origin::operator=(const Origin& rhs)
{
if (this != &rhs)
{
mUser = rhs.mUser;
mSessionId = rhs.mSessionId;
mVersion = rhs.mVersion;
mAddrType = rhs.mAddrType;
mAddress = rhs.mAddress;
}
return *this;
}
SdpContents::Session::Origin::Origin(const Data& user,
const UInt64& sessionId,
const UInt64& version,
AddrType addr,
const Data& address)
: mUser(user),
mSessionId(sessionId),
mVersion(version),
mAddrType(addr),
mAddress(address)
{}
ostream&
SdpContents::Session::Origin::encode(ostream& s) const
{
s << "o="
<< mUser << Symbols::SPACE[0]
<< mSessionId << Symbols::SPACE[0]
<< mVersion << Symbols::SPACE[0]
<< "IN "
<< NetworkType[mAddrType] << Symbols::SPACE[0]
<< mAddress << Symbols::CRLF;
return s;
}
void
SdpContents::Session::Origin::setAddress(const Data& host, AddrType addr)
{
mAddress = host;
mAddrType = addr;
}
void
SdpContents::Session::Origin::parse(ParseBuffer& pb)
{
pb.skipChar('o');
const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
pb.skipToChar(Symbols::SPACE[0]);
pb.data(mUser, anchor);
anchor = pb.skipChar(Symbols::SPACE[0]);
mSessionId = pb.uInt64();
anchor = pb.skipChar(Symbols::SPACE[0]);
mVersion = pb.uInt64();
pb.skipChar(Symbols::SPACE[0]);
pb.skipChar('I');
pb.skipChar('N');
anchor = pb.skipChar(Symbols::SPACE[0]);
pb.skipToChar(Symbols::SPACE[0]);
Data addrType;
pb.data(addrType, anchor);
if (addrType == NetworkType[IP4])
{
mAddrType = IP4;
}
else if (addrType == NetworkType[IP6])
{
mAddrType = IP6;
}
else
{
mAddrType = static_cast<AddrType>(0);
}
anchor = pb.skipChar(Symbols::SPACE[0]);
pb.skipToOneOf(Symbols::CRLF);
pb.data(mAddress, anchor);
skipEol(pb);
}
SdpContents::Session::Email::Email(const Data& address,
const Data& freeText)
: mAddress(address),
mFreeText(freeText)
{}
SdpContents::Session::Email::Email(const Email& rhs)
: mAddress(rhs.mAddress),
mFreeText(rhs.mFreeText)
{}
SdpContents::Session::Email&
SdpContents::Session::Email::operator=(const Email& rhs)
{
if (this != &rhs)
{
mAddress = rhs.mAddress;
mFreeText = rhs.mFreeText;
}
return *this;
}
ostream&
SdpContents::Session::Email::encode(ostream& s) const
{
s << "e=" << mAddress;
if (!mFreeText.empty())
{
s << Symbols::SPACE[0];
s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
}
s << Symbols::CRLF;
return s;
}
// helper to parse email and phone numbers with display name
void parseEorP(ParseBuffer& pb, Data& eOrp, Data& freeText)
{
// =mjh@isi.edu (Mark Handley)
// =mjh@isi.edu
// =Mark Handley <mjh@isi.edu>
// =<mjh@isi.edu>
const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
pb.skipToOneOf("<(\n\r"); // find a left angle bracket "<", a left paren "(", or a CR
switch (*pb.position())
{
case '\n': // Symbols::CR[0]
case '\r': // Symbols::LF[0]
// mjh@isi.edu
// ^
pb.data(eOrp, anchor);
break;
case '<': // Symbols::LA_QUOTE[0]
// Mark Handley <mjh@isi.edu>
// ^
// <mjh@isi.edu>
// ^
pb.data(freeText, anchor);
anchor = pb.skipChar();
pb.skipToEndQuote(Symbols::RA_QUOTE[0]);
pb.data(eOrp, anchor);
pb.skipChar(Symbols::RA_QUOTE[0]);
break;
case '(': // Symbols::LPAREN[0]
// mjh@isi.edu (Mark Handley)
// ^
pb.data(eOrp, anchor);
anchor = pb.skipChar();
pb.skipToEndQuote(Symbols::RPAREN[0]);
pb.data(freeText, anchor);
pb.skipChar(Symbols::RPAREN[0]);
break;
default:
assert(0);
}
}
void
SdpContents::Session::Email::parse(ParseBuffer& pb)
{
pb.skipChar('e');
parseEorP(pb, mAddress, mFreeText);
skipEol(pb);
}
SdpContents::Session::Phone::Phone(const Data& number,
const Data& freeText)
: mNumber(number),
mFreeText(freeText)
{}
SdpContents::Session::Phone::Phone(const Phone& rhs)
: mNumber(rhs.mNumber),
mFreeText(rhs.mFreeText)
{}
SdpContents::Session::Phone&
SdpContents::Session::Phone::operator=(const Phone& rhs)
{
if (this != &rhs)
{
mNumber = rhs.mNumber;
mFreeText = rhs.mFreeText;
}
return *this;
}
ostream&
SdpContents::Session::Phone::encode(ostream& s) const
{
s << "p=" << mNumber;
if (!mFreeText.empty())
{
s << Symbols::SPACE[0];
s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
}
s << Symbols::CRLF;
return s;
}
void
SdpContents::Session::Phone::parse(ParseBuffer& pb)
{
pb.skipChar('p');
parseEorP(pb, mNumber, mFreeText);
skipEol(pb);
}
SdpContents::Session::Connection::Connection(AddrType addType,
const Data& address,
unsigned long ttl)
: mAddrType(addType),
mAddress(address),
mTTL(ttl)
{}
SdpContents::Session::Connection::Connection()
: mAddrType(IP4),
mAddress(Data::Empty),
mTTL(0)
{}
SdpContents::Session::Connection::Connection(const Connection& rhs)
: mAddrType(rhs.mAddrType),
mAddress(rhs.mAddress),
mTTL(rhs.mTTL)
{
}
SdpContents::Session::Connection&
SdpContents::Session::Connection::operator=(const Connection& rhs)
{
if (this != &rhs)
{
mAddrType = rhs.mAddrType;
mAddress = rhs.mAddress;
mTTL = rhs.mTTL;
}
return *this;
}
ostream&
SdpContents::Session::Connection::encode(ostream& s) const
{
s << "c=IN "
<< NetworkType[mAddrType] << Symbols::SPACE[0] << mAddress;
if (mTTL)
{
s << Symbols::SLASH[0] << mTTL;
}
s << Symbols::CRLF;
return s;
}
void
SdpContents::Session::Connection::setAddress(const Data& host, AddrType addr)
{
mAddress = host;
mAddrType = addr;
}
void
SdpContents::Session::Connection::parse(ParseBuffer& pb)
{
pb.skipChar('c');
pb.skipChar(Symbols::EQUALS[0]);
pb.skipChar('I');
pb.skipChar('N');
const char* anchor = pb.skipChar(Symbols::SPACE[0]);
pb.skipToChar(Symbols::SPACE[0]);
Data addrType;
pb.data(addrType, anchor);
if (addrType == NetworkType[IP4])
{
mAddrType = IP4;
}
else if (addrType == NetworkType[IP6])
{
mAddrType = IP6;
}
else
{
mAddrType = static_cast<AddrType>(0);
}
anchor = pb.skipChar();
pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
pb.data(mAddress, anchor);
mTTL = 0;
if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
{
pb.skipChar();
mTTL = pb.integer();
}
// multicast dealt with above this parser
if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
{
skipEol(pb);
}
}
SdpContents::Session::Bandwidth::Bandwidth(const Data& modifier,
unsigned long kbPerSecond)
: mModifier(modifier),
mKbPerSecond(kbPerSecond)
{}
SdpContents::Session::Bandwidth::Bandwidth(const Bandwidth& rhs)
: mModifier(rhs.mModifier),
mKbPerSecond(rhs.mKbPerSecond)
{}
SdpContents::Session::Bandwidth&
SdpContents::Session::Bandwidth::operator=(const Bandwidth& rhs)
{
if (this != &rhs)
{
mModifier = rhs.mModifier;
mKbPerSecond = rhs.mKbPerSecond;
}
return *this;
}
ostream&
SdpContents::Session::Bandwidth::encode(ostream& s) const
{
s << "b="
<< mModifier
<< Symbols::COLON[0] << mKbPerSecond
<< Symbols::CRLF;
return s;
}
void
SdpContents::Session::Bandwidth::parse(ParseBuffer& pb)
{
pb.skipChar('b');
const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
if (*pb.position() == Symbols::COLON[0])
{
pb.data(mModifier, anchor);
anchor = pb.skipChar(Symbols::COLON[0]);
mKbPerSecond = pb.integer();
skipEol(pb);
}
else
{
pb.fail(__FILE__, __LINE__);
}
}
SdpContents::Session::Time::Time(unsigned long start,
unsigned long stop)
: mStart(start),
mStop(stop)
{}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -