reSIProcate学习笔记(四)


Headers、ParameterTypes、ParserCategories

从ParameterTypes.hxx谈起:

class ParamBase
{
   public:
      virtual ~ParamBase() {}
      virtual ParameterTypes::Type getTypeNum() const = 0;
      virtual const char* name() const = 0;
};

template<class T>
class Param : virtual public ParamBase
{};

类Param仍然是一个抽象类,其方法在各类具体参数中实现。

#define defineParam(_enum, _name, _type, _headertype, _RFC_ref_ignored) \
    class _enum##_Param : public Param<_headertype>                     \
    {                                                                   \
    public:                                                             \
         typedef _type Type;                                            \
         typedef _type::Type DType;                                     \
         virtual ParameterTypes::Type getTypeNum() const;               \
         virtual const char* name() const { return _name; }             \
         _enum##_Param();                                               \
    };                                                                  \
    extern _enum##_Param p_##_enum

每一个该宏定义了一个继承Param模板类的具体参数类,例如

defineParam(data, “data”, ExistsParameter, NameAddr, “RFC 3840”); 宏展开之后的样子如下:

class data_Param : public Param<NameAddr>
{
public:
    typedef ExistsParameter Type;
    typedef ExistsParameter::Type DType;
    virtual ParameterTypes::Type getTypeNum() const;
    virtual const char* name() const { return "data"; }
    data_Param();
};
extern data_Param p_data

在ParameterTypes.cxx中的defineParam宏则专门负责头文件中具体化后的类中未实现的方法的实现

#define defineParam(_enum, _name, _type, _headertype, _RFC_ref_ignored)         \
ParameterTypes::Type                                                            \
_enum##_Param::getTypeNum() const {return ParameterTypes::_enum;}               \
_enum##_Param::_enum##_Param()                                                  \
{                                                                               \
    _headertype::ParameterFactories[ParameterTypes::_enum] = Type::decode;      \
    ParameterTypes::ParameterNames[ParameterTypes::_enum] = _name;              \
}                                                                               \
_enum##_Param resip::p_##_enum

defineParam(data, “data”, ExistsParameter, NameAddr, “RFC 3840”); 在此处展开后结果则为:

ParameterTypes::Type data_Param::getTypeNum() const {return ParameterTypes::data;}
data_Param::data_Param()
{
    NameAddr::ParameterFactories[ParameterTypes::data] = Type::decode;
    ParameterTypes::ParameterNames[ParameterTypes::data] = "data";
}
data_Param resip::p_data

此举大大提高了代码利用率。

类ParameterTypes定义在文件ParameterTypeEnums.hxx中,此文件中的defineParam宏非常简单:

#define defineParam(_enum, _name, _type, _rfc)  _enum

类ParameterTypes的枚举成员Type包含了各类头的枚举值,其中最后一个枚举值是MAX_PARAMETER,其值表示Type中枚举种类数目;其静态成员数组static Data ParameterNames[MAX_PARAMETER]; 由defineParam宏中第二个参数值_name来索引,此数组在ParameterTypes.cxx中的初始化语句:

Data ParameterTypes::ParameterNames[ParameterTypes::MAX_PARAMETER] = {“PARAMETER?”};

类ParameterTypes包含成员函数指针Factory和存储其的静态数组ParameterFactories

/* @param ParameterTypes::Type class on which to call decode to get the Parameter*
   @param ParseBuffer buffer to parse
   @param terminators The terminator characters to use
   @return ParameterTypes::Type.decode() defined in each class type. */
typedef Parameter* (*Factory)(ParameterTypes::Type, ParseBuffer&, const std::bitset<256>& terminators, PoolBase* pool);

static Factory ParameterFactories[MAX_PARAMETER];

该静态数组在ParameterTypes.cxx中的初始化语句:

ParameterTypes::Factory ParameterTypes::ParameterFactories[ParameterTypes::MAX_PARAMETER] = {0};

类ParameterTypes还有一个静态成员函数getType(),用来将指向HeaderFieldValue raw buffer的指针转换成Type枚举类型。

ParameterTypes::Type ParameterTypes::getType(const char* pname, unsigned int len)
{

const struct params* p;
p = ParameterHash::in_word_set(pname, len);
return p ? p->type : ParameterTypes::UNKNOWN;

}

结构params的定义在ParameterHash.hxx中:

struct params { char *name; ParameterTypes::Type type; };

class ParameterHash
{
private: static inline unsigned int hash (const char *str, unsigned int len);
public: static const struct params *in_word_set (const char *str, unsigned int len);
};

类Parameter的完整定义如下:

class Parameter
{
   public:
      Parameter(ParameterTypes::Type type);
      virtual ~Parameter() {}
      ParameterTypes::Type getType() const;
      virtual const Data& getName() const;
      virtual Parameter* clone() const = 0;
      virtual EncodeStream& encode(EncodeStream& stream) const = 0;
      virtual bool isQuoted() const { return false; } // only on DataParameter
      virtual void setQuoted(bool) { }; // only on DataParameter
   protected:
      Parameter(const Parameter& other) : mType(other.mType) {};
      Parameter& operator=(const Parameter& other); // don't define
   private:
      ParameterTypes::Type mType;
};

该类的唯一数据成员就是ParameterTypes,而ParameterTypes.hxx和ParameterTypes.cxx中的defineParam宏的第三个参数可传入的值ExistsParameter、QuotedDataParameter、UInt32Parameter、ExistsOrDataParameter、BranchParameter、RportParameter都直接或间接继承于Parameter类,可以认为类Parameter就是为各种更为具体的参数类型类提供了统一的操作方法并且使得各具体参数类型类携带了表明自身参数类型的ParameterTypes成员。

既然defineParam宏的第三个参数可传入的值都继承于Parameter类,那么第四个参数可传入的值NameAddr、Uri、GenericUri、Mime、Auth、Via、Token、TokenOrQuotedStringCategory、CallID、ExpiresCategory等又是继承于哪个类呢?答案是ParserCategory类。

要分析ParserCategory类,首先得弄清楚Headers类、HeaderFieldValue类。

定义各种Headers的方式和定义各种ParameterTypes的方式十分类似,在HeaderTypes.hxx中定义了Headers类,其中的枚举成员Type担任起了表示各种Header类型的任务,同样,最后的枚举值MAX_HEADERS表示目前Header类型的数目,其中的一堆宏定义:

#define defineHeader(_enum, _name, _type, _rfc)  _enum
#define defineMultiHeader(_enum, _name, _type, _rfc)  _enum

类Headers的其他成员全是静态的:

// get enum from header name
static Type getType(const char* name, int len);
static bool isCommaTokenizing(Type type);
static bool isCommaEncoding(Type type);
static const Data& getHeaderName(int);
static bool isMulti(Type type);
// treat as private
static bool CommaTokenizing[MAX_HEADERS+1];
static bool CommaEncoding[MAX_HEADERS+1];
static Data HeaderNames[MAX_HEADERS+1];
static bool Multi[MAX_HEADERS+1];

在看Header.hxx前,先看看HeaderFieldValue.hxx,类HeaderFieldValue只有三个数据成员:

const char* mField;
unsigned int mFieldLength;
bool mMine;

布尔值mMine表示所有权,在其成员函数init()和clear()中,仅当mMine为true时才delete []mField;

类HeaderFieldValueList从类名上就可以看出是存储一系列HeaderFieldValue的结构,其私有成员:

typedef std::vector<HeaderFieldValue, StlPoolAllocator<HeaderFieldValue, PoolBase > >  ListImpl;

ListImpl mHeaders;
PoolBase* mPool;
ParserContainerBase* mParserContainer;

static const HeaderFieldValueList Empty;

vector方法的重写:

/* READ THIS CAREFULLY BEFORE USING THIS FUNCTION
@param own Specifies whether the created HeaderFieldValue will take ownership of the buffer passed. This will never make a copy of the buffer; if own == false, the HeaderFieldValue will retain the same reference that it would if own == true. The only difference is that if own == false, the buffer will not be deleted when the HeaderFieldValue goes away/releases its reference, while if own==true the buffer will be deleted. This means that no matter what you pass for this param, you must ensure that the buffer is not deleted during the lifetime of this HeaderFieldValueList. */
void push_back(const char* buffer, size_t length, bool own)
{
mHeaders.push_back(HeaderFieldValue::Empty);
mHeaders.back().init(buffer, length, own);
}
void pop_back() { mHeaders.pop_back(); }
HeaderFieldValue* front() { return &mHeaders.front(); }
HeaderFieldValue* back() { return &mHeaders.back(); }

现在来看Header.hxx,其中有HeaderBase类的完整定义,估计是和ParamBase类作用一样,将其完整定义摘下:

class HeaderBase
{
   public:
      virtual ~HeaderBase() {}
      virtual Headers::Type getTypeNum() const = 0;
      virtual void merge(SipMessage&, const SipMessage&) = 0;
      
      static HeaderBase* getInstance(Headers::Type typenum)
      {
         return theHeaderInstances[typenum+1];
      }
      
      virtual ParserContainerBase* makeContainer(HeaderFieldValueList* hfvs) const = 0;
   protected:
      static HeaderBase* theHeaderInstances[Headers::MAX_HEADERS+1];
};

下面隆重推出重要的两个宏:defineHeader和defineMultiHeader:

#define defineHeader(_enum, _name, _type, _rfc)                 \
class H_##_enum : public HeaderBase                             \
{                                                               \
   public:                                                      \
      RESIP_HeapCount(H_##_enum);                               \
      enum {Single = true};                                     \
      typedef _type Type;                                       \
      UnusedChecking(_enum);                                    \
      static Type& knownReturn(ParserContainerBase* container); \
      virtual ParserContainerBase* makeContainer(HeaderFieldValueList* hfvs) const;       \
      virtual Headers::Type getTypeNum() const;                 \
      virtual void merge(SipMessage&, const SipMessage&);       \
      H_##_enum();                                              \
};                                                              \
extern H_##_enum h_##_enum

defineHeader(From, “From”, NameAddr, “RFC 3261”); 展开之后的样子是:

class H_From : public HeaderBase
{
   public:
      RESIP_HeapCount(H_From);
      enum {Single = true};
      typedef NameAddr Type;
      UnusedChecking(From);
      static Type& knownReturn(ParserContainerBase* container);
      virtual ParserContainerBase* makeContainer(HeaderFieldValueList* hfvs) const;
      virtual Headers::Type getTypeNum() const;
      virtual void merge(SipMessage&, const SipMessage&);
      H_From();
};
extern H_From h_From

#define defineMultiHeader(_enum, _name, _type, _rfc)            \
class H_##_enum##s : public HeaderBase                          \
{                                                               \
   public:                                                      \
      RESIP_HeapCount(H_##_enum##s);                            \
      enum {Single = false};                                    \
      typedef ParserContainer<_type> Type;                      \
      typedef _type ContainedType;                      \
      MultiUnusedChecking(_enum);                               \
      static Type& knownReturn(ParserContainerBase* container); \
      virtual ParserContainerBase* makeContainer(HeaderFieldValueList* hfvs) const;       \
      virtual Headers::Type getTypeNum() const;                 \
      virtual void merge(SipMessage&, const SipMessage&);       \
      H_##_enum##s();                                           \
};                                                              \
extern H_##_enum##s h_##_enum##s

defineMultiHeader(CallInfo, “Call-Info”, GenericUri, “RFC 3261”); 展开之后的样子:

class H_CallInfos : public HeaderBase
{
   public:
      RESIP_HeapCount(H_CallInfos);
      enum {Single = false};
      typedef ParserContainer<GenericUri> Type;
      typedef GenericUri ContainedType;
      MultiUnusedChecking(CallInfo);
      static Type& knownReturn(ParserContainerBase* container);
      virtual ParserContainerBase* makeContainer(HeaderFieldValueList* hfvs) const;
      virtual Headers::Type getTypeNum() const;
      virtual void merge(SipMessage&, const SipMessage&);
      H_CallInfos();
};
extern H_CallInfos h_CallInfos

其中未实现的成员函数势必交给了Headers.cxx中的同名宏去实现:

#define defineHeader(_enum, _name, _type, _reference)                  \
Headers::Type                                                          \
H_##_enum::getTypeNum() const {return Headers::_enum;}                 \
                                                                       \
void H_##_enum::merge(SipMessage& target, const SipMessage& embedded)  \
{                                                                      \
   if (embedded.exists(*this))                                         \
   {                                                                   \
      target.header(*this) = embedded.header(*this);                   \
   }                                                                   \
}                                                                      \
                                                                       \
H_##_enum::H_##_enum()                                                 \
{                                                                      \
   Headers::CommaTokenizing[Headers::_enum+1] = bool(Type::commaHandling & ParserCategory::CommasAllowedOutputMulti);\
   Headers::CommaEncoding[Headers::_enum+1] = bool(Type::commaHandling & 2); \
   Headers::HeaderNames[Headers::_enum+1] = _name;                     \
   Headers::Multi[Headers::_enum+1] = false;                           \
   HeaderBase::theHeaderInstances[Headers::_enum+1] = this;            \
}                                                                      \
                                                                       \
_type&                                                                 \
H_##_enum::knownReturn(ParserContainerBase* container)                 \
{                                                                      \
   return dynamic_cast<ParserContainer<_type>*>(container)->front();   \
}                                                                      \
                                                                       \
ParserContainerBase*                                                   \
H_##_enum::makeContainer(HeaderFieldValueList* hfvs) const             \
{                                                                      \
   return new ParserContainer<_type>(hfvs, Headers::_enum);            \
}                                                                      \
                                                                       \
H_##_enum resip::h_##_enum

defineHeader(From, “From”, NameAddr, “RFC 3261”); 展开之后的样子是:

Headers::Type H_From::getTypeNum() const {return Headers::From;}
void H_From::merge(SipMessage& target, const SipMessage& embedded)
{
   if (embedded.exists(*this))
   {
      target.header(*this) = embedded.header(*this);
   }
}

H_From::H_From()
{
   Headers::CommaTokenizing[Headers::From+1] = bool(Type::commaHandling & ParserCategory::CommasAllowedOutputMulti);
   Headers::CommaEncoding[Headers::From+1] = bool(Type::commaHandling & 2);
   Headers::HeaderNames[Headers::From+1] = "From";
   Headers::Multi[Headers::From+1] = false;
   HeaderBase::theHeaderInstances[Headers::From+1] = this;
}

NameAddr& H_From::knownReturn(ParserContainerBase* container)
{
   return dynamic_cast<ParserContainer<NameAddr>*>(container)->front();
}
ParserContainerBase* H_From::makeContainer(HeaderFieldValueList* hfvs) const
{
   return new ParserContainer<NameAddr>(hfvs, Headers::From);
}

H_From resip::h_From

#define defineMultiHeader(_enum, _name, _type, _reference)               \
   Headers::Type                                                         \
H_##_enum##s::getTypeNum() const {return Headers::_enum;}                \
                                                                         \
void H_##_enum##s::merge(SipMessage& target, const SipMessage& embedded) \
{                                                                        \
   if (embedded.exists(*this))                                           \
   {                                                                     \
      target.header(*this).append(embedded.header(*this));               \
   }                                                                     \
}                                                                        \
                                                                         \
H_##_enum##s::H_##_enum##s()                                             \
{                                                                        \
   Headers::CommaTokenizing[Headers::_enum+1] = bool(Type::value_type::commaHandling & ParserCategory::CommasAllowedOutputMulti); \
   Headers::CommaEncoding[Headers::_enum+1] = bool(Type::value_type::commaHandling & 2); \
   Headers::HeaderNames[Headers::_enum+1] = _name;                       \
   Headers::Multi[Headers::_enum+1] = true;                              \
   HeaderBase::theHeaderInstances[Headers::_enum+1] = this;              \
}                                                                        \
                                                                         \
ParserContainer<_type>&                                                  \
H_##_enum##s::knownReturn(ParserContainerBase* container)                \
{                                                                        \
   return *dynamic_cast<ParserContainer<_type>*>(container);             \
}                                                                        \
                                                                         \
ParserContainerBase*                                                     \
H_##_enum##s::makeContainer(HeaderFieldValueList* hfvs) const            \
{                                                                        \
   return new ParserContainer<_type>(hfvs, Headers::_enum);              \
}                                                                        \
                                                                         \
H_##_enum##s resip::h_##_enum##s

defineMultiHeader(CallInfo, “Call-Info”, GenericUri, “RFC 3261”); 展开之后的样子:

Headers::Type H_CallInfos::getTypeNum() const {return Headers::CallInfo;}

void H_CallInfos::merge(SipMessage& target, const SipMessage& embedded)
{
   if (embedded.exists(*this))
   {
      target.header(*this).append(embedded.header(*this));
   }
}

H_CallInfos::H_CallInfos()
{
   Headers::CommaTokenizing[Headers::CallInfo+1] = bool(Type::value_type::commaHandling & ParserCategory::CommasAllowedOutputMulti);
   Headers::CommaEncoding[Headers::CallInfo+1] = bool(Type::value_type::commaHandling & 2);
   Headers::HeaderNames[Headers::CallInfo+1] = "CallInfo";
   Headers::Multi[Headers::CallInfo+1] = true;
   HeaderBase::theHeaderInstances[Headers::CallInfo+1] = this;
}

ParserContainer<GenericUri>&
H_CallInfos::knownReturn(ParserContainerBase* container)
{
   return *dynamic_cast<ParserContainer<GenericUri>*>(container);
}

ParserContainerBase*
H_CallInfos::makeContainer(HeaderFieldValueList* hfvs) const
{
   return new ParserContainer<GenericUri>(hfvs, Headers::_enum);
}

H_CallInfos resip::h_CallInfos

Headers::getType()也是根据哈希表实现:

struct headers { char *name; Headers::Type type; };

class HeaderHash
{
private: static inline unsigned int hash (const char *str, unsigned int len);
public: static const struct headers *in_word_set (const char *str, unsigned int len);
};

Headers::Type Headers::getType(const char* name, int len) {

const struct headers* p;
p = HeaderHash::in_word_set(name, len);
return p ? Headers::Type(p->type) : Headers::UNKNOWN;

}

现在来分析ParserCategory类(@brief  Base class for all SIP grammar elements that can have parameters.),其继承于LazyParser类(@brief  The base-class for all lazily-parsed SIP grammar elements.),所有数据成员如下:

typedef std::vector<Parameter*, StlPoolAllocator<Parameter*, PoolBase> > ParameterList;
ParameterList mParameters;
ParameterList mUnknownParameters;
PoolBase* mPool;
Headers::Type mHeaderType;

再看其构造函数:

ParserCategory(const HeaderFieldValue& headerFieldValue, Headers::Type type, PoolBase* pool = 0);

不同类型Header的解析方式:

/* NoCommaTokenizing:      commas do not indicate a new header value
CommasAllowedOutputMulti:  multi headers can be received with commas but output them on separate lines.
CommasAllowedOutputCommas: multi headers can be received with commas and will always output with commas when parsed. */
enum {NoCommaTokenizing = 0, CommasAllowedOutputMulti = 1, CommasAllowedOutputCommas = 3};

判断给定参数类型是否支持解析,形参是所有参数类型基类的引用

/* @brief Checks for the existence of a natively supported parameter.
@param paramType The accessor token for the parameter.
@return true if the parameter is present. */
inline bool exists(const ParamBase& paramType) const
{
checkParsed();
return (getParameterByEnum(paramType.getTypeNum()) != NULL);
}

/* @brief Accessor for non-natively-supported parameter types. Will create the parameter if it does not exist.
@param param The runtime constructed parameter accessor.
@return The parameter, as a raw Data. */
Data& param(const ExtensionParameter& param);

现在再将类注释抄摘如下:

/* The pattern for accessing the parameters in a ParserCategory is very similar to accessing headers in a SipMessage. Each parameter type has an access token class (a subclass of ParamBase), and a corresponding ParserCategory::param() function that takes an instance of that subclass as an argument, and returns the correct type for that parameter. Common examples of access-token include p_tag, p_q, p_lr, p_expires, p_branch, etc.
@code
NameAddr& contact = sip.header(h_Contacts).front();
if(contact.exists(p_q))
{
QValueParameter& q = contact.param(p_q);
// do stuff with q
}

NameAddr& to = sip.header(h_To);
if(to.exists(p_tag))
{
DataParameter& toTag = to.param(p_tag);
// do stuff with toTag
}

Via& topVia = sip.header(h_Vias).front();
if(topVia.exists(p_branch))
{
BranchParameter& branch = topVia.param(p_branch);
// do stuff with branch
}
@endcode

Note the calls to ParserCategory::exists() in the code above; calling ParserCategory::param() when the relevant parameter doesn’t exist will either cause the parameter to be created, or an exception to be thrown (if you’re working with a const reference).

In some cases, you will need to access parameter-types that are not natively supported by the stack (ie, don’t have an access-token). ExtensionParameter will allow you to construct an access-token at runtime that will retrieve the parameter as a raw Data. Here’s an example:

@code
// We need to access the foo parameter on the Request-Uri
RequestLine& rLine = sip.header(h_RequestLine);
static ExtensionParameter p_foo(“foo”);
if(rLine.uri().exists(p_foo))
{
Data& foo = rLine.uri().param(p_foo);
}
@endcode
*/

最后瞥一瞥ParserContainerBase类和ParserContainer类,前者是一个抽象类,内含嵌套类HeaderKit,而HeaderKit拥有两个数据成员:

ParserCategory* pc;
HeaderFieldValue hfv;

ParserContainerBase类把其中的HeaderKit组织成了vector形式,并取别名为Parsers:

typedef std::vector<HeaderKit, StlPoolAllocator<HeaderKit, PoolBase> > Parsers;
Parsers mParsers;
PoolBase* mPool;

这样一来,ParserContainerBase明确其实地成为了一系列ParserCategory和HeaderFieldValue对象的容器,而ParserContainer类(@brief  Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact, Via, etc).)继承于ParserContainerBase,并被设计成为类模板,其主要的构造函数如下:

ParserContainer(HeaderFieldValueList* hfvs, Headers::Type type, PoolBase& pool)
         : ParserContainerBase(type, pool)
{
    mParsers.reserve(hfvs->size());
    for (HeaderFieldValueList::iterator i = hfvs->begin(); i != hfvs->end(); i++)
    {
         // create, store without copying -- 
         // keeps the HeaderFieldValue from reallocating its buffer
         mParsers.push_back(HeaderKit::Empty);
         mParsers.back().hfv.init(i->getBuffer(),i->getLength(),false);
    }
}

一系列由ParserCategory类派生出来的类都被包含在了ParserCategories.hxx文件中:

#include “resip/stack/Auth.hxx”
#include “resip/stack/CSeqCategory.hxx”
#include “resip/stack/CallId.hxx”
#include “resip/stack/DateCategory.hxx”
#include “resip/stack/ExpiresCategory.hxx”
#include “resip/stack/GenericUri.hxx”
#include “resip/stack/IntegerCategory.hxx”
#include “resip/stack/UInt32Category.hxx”
#include “resip/stack/Mime.hxx”
#include “resip/stack/NameAddr.hxx”
#include “resip/stack/PrivacyCategory.hxx”
#include “resip/stack/RAckCategory.hxx”
#include “resip/stack/RequestLine.hxx”
#include “resip/stack/StatusLine.hxx”
#include “resip/stack/StringCategory.hxx”
#include “resip/stack/Token.hxx”
#include “resip/stack/Via.hxx”
#include “resip/stack/WarningCategory.hxx”
#include “resip/stack/TokenOrQuotedStringCategory.hxx”

因此,Headers.hxx中只需#include “resip/stack/ParserCategories.hxx”就将所有HeaderType对应的Parser类都包含了进来。

而ParameterTypes.hxx文件中将所有具体的参数类型文件都包含了进来:

#include “resip/stack/BranchParameter.hxx”
#include “resip/stack/DataParameter.hxx”
#include “resip/stack/ExistsOrDataParameter.hxx”
#include “resip/stack/QuotedDataParameter.hxx”
#include “resip/stack/IntegerParameter.hxx”
#include “resip/stack/UInt32Parameter.hxx”
#include “resip/stack/QValueParameter.hxx”
#include “resip/stack/ExistsParameter.hxx”
#include “resip/stack/ParameterTypeEnums.hxx”
#include “resip/stack/RportParameter.hxx”

在ParserCategory.hxx中则有:#include “resip/stack/ParameterTypes.hxx”,因此Headers.hxx已经间接#include进来了所有Header的参数类型。

Leave a comment

邮箱地址不会被公开。 必填项已用*标注