这章的翻译自己理解的多,并非逐字翻译。
Chapter 3:Message Elements
3.1 Uniform Resource Indicator (URI)
pjsip里的URI几乎都是用面向对象的方式(有的人说的基于对象)建模的。所以URI可以统一的被栈处理, 引入新类型的URI也很容易。
3.1.1 URI “Class Diagram”
下面的图表展示了URI的设计
下一节将详细介绍各种对象。
3.1.2 URI Context
uri context指明何处使用uri(比如request line, From/To header)。context也指明了哪里允许出现uri的元素。比如,传输的参数不允许出现在From/To的头里。
在PJSIP里context必须在uri打印进缓冲区或比较两个uri的时候指定。这样的话,打印和比较的时候就会忽略那些不允许出现在指定的context中uri。
3.1.3 Base URI
pjsip_uri的结构体中包含了全部uri可共享的属性。因此所有的类型都可以放进pjsip_uri里统一操作。
struct pjsip_uri
{
pjsip_uri_vptr *vptr;
};
pjsip_uri_vptr指定virtual函数表,它的成员由各类型的uri定义,不建议应用程序直接调用这些函数指针,而是使用更易读的API(并且这样可以节省一些类型)。
struct pjsip_uri_vptr
{
const pj_str_t* (*p_get_scheme) ( const pjsip_uri *uri);
pjsip_uri* (*p_get_uri) ( pjsip_uri *uri);
int (*p_print) ( pjsip_uri_context_e context,
const pjsip_uri *uri,
char *buf, pj_size_t size);
pj_status_t (*p_compare) ( pjsip_uri_context_e context,
const pjsip_uri *uri1, const pjsip_uri *uri2);
pjsip_uri * (*p_clone) ( pj_pool_t *pool, const pjsip_uri *uri);
};
下面的uri函数适用于所有类型的uri对象。这些函数通常以内联函数的形式实现,在URI的虚函数表中调用相应的函数指针。
const pj_str_t* pjsip_uri_get_scheme( const pjsip_uri *uri );
Get the URI scheme string (e.g. “sip”, “sips”, “tel”, etc.).
pjsip_uri* pjsip_uri_get_uri( pjsip_uri *uri );
Get the URI object.通常,除了name address对象将返回name address对象内部的URI之外,所有URI对象都将返回自身。
pj_status_t pjsip_uri_cmp( pjsip_uri_context_e context,
const pjsip_uri *uri1,
const pjsip_uri *uri2);
Compare uri1 and uri2 according to the specified context
比较的时候会忽略那些context中不允许的uri。如果uri相同会返回PJ_SUCCESS。
int pjsip_uri_print( pjsip_uri_context_e context,
const pjsip_uri *uri,
char *buffer,
pj_size_t max_size);
根据指定的context打印uri进缓冲区。context中不允许的uri不会打印。
pjsip_uri* pjsip_uri_clone( pj_pool_t *pool, const pjsip_uri *uri );
用指定的池来深度克隆uri
3.1.4 SIP and SIPS URI
pjsip_sip_uri结构体描述了sip和sips URI的方案。 <pjsip/sip_uri.h>中声明。
struct pjsip_sip_uri
{
pjsip_uri_vptr *vptr; // Pointer to virtual function table.
pj_str_t user; // Optional user part.
pj_str_t passwd; // Optional password part.
pj_str_t host; // Host part, always exists.
int port; // Optional port number, or zero.
pj_str_t user_param; // Optional user parameter
pj_str_t method_param; // Optional method parameter.
pj_str_t transport_param; // Optional transport parameter.
int ttl_param; // Optional TTL param, or -1.
int lr_param; // Optional loose routing param, or 0
pj_str_t maddr_param; // Optional maddr param
pjsip_param other_param; // Other parameters as list.
pjsip_param header_param; // Optional header parameters as list.
};
下面的函数是专门用于SIP/SIPS URI对象的。除了这些功能之外,应用程序还可以使用前一节中描述的基本URI函数来处理SIP和SIPS URI。
pjsip_sip_uri* pjsip_sip_uri_create( pj_pool_t *pool, pj_bool_t secure );
用指定的pool来创建新的SIP URL。如果设置了非零标志位,则创建SIPS URL。该函数将URL的vptr成员设置为SIP或SIPS vptr,并将所有其他成员设置为空值。
void pjsip_sip_uri_init( pjsip_sip_uri *url, pj_bool_t secure );
初始化SIP URL 结构体
void pjsip_sip_uri_assign( pj_pool_t *pool,
pjsip_sip_uri *url,
const pjsip_sip_uri *rhs );
执行rhs到url的深度复制
3.1.5 Tel URI
pjsip_tel_ur 结构体描述tel:URL, <pjsip/sip_tel_uri.h>中声明。
struct pjsip_tel_uri
{
pjsip_uri_vptr *vptr; // Pointer to virtual function table.
pj_str_t number; // Global or local phone number
pj_str_t context; // Phone context (for local number).
pj_str_t ext_param; // Extension param.
pj_str_t isub_param; // ISDN sub-address param.
pjsip_param other_param; // Other parameters.
};
下面的函数专门用于TEL URI,除了这些功能之外,应用程序还可以使用前一节中描述的基本URI函数来处理TEL URI。
pjsip_tel_uri* pjsip_tel_uri_create( pj_pool_t *pool );
创建新的 tel: URI
int pjsip_tel_nb_cmp( const pj_str_t *nb1, const pj_str_t *nb2 );
这个函数根据RFC3966(tel:URI)的规则比较两个电话号码是否相同。它能区分全局和局部数字,并且忽略可视的分隔符。
3.1.6 Name Address
一个name address( pjsip_name_addr)并非真正定义一个uri类型,而是封装现有的uri(如sip uri),然后添加display name。
struct pjsip_name_addr
{
pjsip_uri_vptr *vptr; // Pointer to virtual function table.
pj_str_t display; // Display name.
pjsip_uri *uri; // The URI.
};
下面的函数专门用于name address URI对象。除了这些功能之外,应用程序还可以使用前一节中描述的基本URI函数来处理name address对象。
pjsip_name_addr* pjsip_name_addr_create( pj_pool_t *pool );
创建新的name address。设置初始化虚函数表指针,空白的display name,其他uri成员为NULL。
void pjsip_name_addr_assign( pj_pool_t *pool,
pjsip_name_addr *name_addr,
const pjsip_name_addr *rhs );
复制rhs到name_addr
3.1.7 Sample URI Manipulation Program
#include <pjlib.h>
#include <pjsip_core.h>
#include <stdlib.h> // exit()
static pj_caching_pool cp;
static void my_error_exit(const char *title, pj_status_t errcode)
{
char errbuf[80];
pjsip_strerror(errcode, errbuf, sizeof(errbuf));
PJ_LOG(3,(“main”, “%s: %s”, title, errbuf));
exit(1);
}
static void my_init_pjlib(void)
{
pj_status_t status;
// Init PJLIB
status = pj_init();
if (status != PJ_SUCCESS) my_error_exit(“pj_init() error”, status);
// Init caching pool factory.
pj_caching_pool_init( &cp, &pj_pool_factory_default_policy, 0);
}
static void my_print_uri( const char *title, pjsip_uri *uri )
{
char buf[80];
int len;
len = pjsip_uri_print( PJSIP_URI_IN_OTHER, uri, buf, sizeof(buf)-1);
if (len < 0)
my_error_exit(“Not enough buffer to print URI”, -1);
buf[len] = ‘\0’;
PJ_LOG(3, (“main”, “%s: %s”, title, buf));
}
int main()
{
pj_pool_t *pool;
pjsip_name_addr *name_addr;
pjsip_sip_uri *sip_uri;
// Init PJLIB
my_init_pjlib();
// Create pool to allocate memory
pool = pj_pool_create(&cp.factory, “mypool”, 4000, 4000, NULL);
if (!pool) my_error_exit(“Unable to create pool”, PJ_ENOMEM);
// Create and initialize a SIP URI instance
sip_uri = pjsip_sip_uri_create(pool, PJ_FALSE);
sip_uri->user = pj_str(“alice”);
sip_uri->host = pj_str(“sip.example.com”);
my_print_uri(“The SIP URI is”, (pjsip_uri*)sip_uri);
// Create a name address to put the SIP URI
name_addr = pjsip_name_addr_create(pool);
name_addr->uri = (pjsip_uri*) sip_uri;
name_addr->display = “Alice Cooper”;
my_print_uri(“The name address is”, (pjsip_uri*)name_addr);
// Done
}
3.2 SIP Methods
3.2.1 SIP Method Representation (pjsip_method)
pjsip中的sip method可以扩展,不需要重编译库就可以支持。
struct pjsip_method
{
pjsip_method_e id; // Method ID, from pjsip_method_e.
pj_str_t name; // Method name, which will always contain the method string.
};
PJSIP核心库只声明核心sip标准(RFC 3261)指定的方法。对于这些核心的方法,pjsip_method的id字段将包含以下枚举的特定值:
enum pjsip_method_e
{
PJSIP_INVITE_METHOD,
PJSIP_CANCEL_METHOD,
PJSIP_ACK_METHOD,
PJSIP_BYE_METHOD,
PJSIP_REGISTER_METHOD,
PJSIP_OPTIONS_METHOD,
PJSIP_OTHER_METHOD,
};
这些枚举中没有指定的方法,都是用 PJSIP_OTHER_METHOD这个值。因此,应用程序通过pjsip_method的name字段来获得相应的方法。
3.2.2 SIP Method API
下面的参数可以用来处理PJSIP的sip方法对象。
void pjsip_method_init( pjsip_method *method, pj_pool_t *pool,
const pj_str_t *method_name );
从字符串中初始化method,初始化method字段的id为一个正确值。
void pjsip_method_init_np( pjsip_method *method,
pj_str_t *method_name );
从method_name字符串里面初始化method而不复制字符串( (np stands for no pool))。id字段初始化为相对应的值。
void pjsip_method_set( pjsip_method *method,
pjsip_method_id_e method_id );
从method ID的枚举里初始化method。name字段初始化为相对应的值
void pjsip_method_copy( pj_pool_t *pool,
pjsip_method *method,
const pjsip_method *rhs );
复制rhs到method。
int pjsip_method_cmp( const pjsip_method *method1,
const pjsip_method *method2 );
比较method1和method2是否相等。相等返回0,小于返回-1,大于返回1。
3.3 Header Fields
pjsip共享公共头属性的所有头字段,比如 header type,name,short name和虚函数表。因此所有的头字段都被栈统一处理。
3.3.1 Header “Class Diagram”
下面的图标展示了PJSIP header 类图的一部分,实际的header比这多。PJSIP库实现了核心SIP规范(RFC 3261)的所有header。其他的header将在PJSIP的扩展模块实现。
如上图所示,每一个指定的header通常对特定的header只提供一个函数,也就是说函数创建header实例
3.3.2 Header Structure
为了确保头字段包含公共头属性且这些属性都是正确统一的内存分配,header声明时候必须调用宏 PJSIP_DECL_HDR_MEMBER作为header的第一个成员字段,指定header name作为宏的一个参数。
#define PJSIP_DECL_HDR_MEMBER(hdr) \
/** List members. */ \
PJ_DECL_LIST_MEMBER(hdr); \
/** Header type */ \
pjsip_hdr_e type; \
/** Header name. */ \
pj_str_t name; \
/** Header short name version. */ \
pj_str_t sname; \
/** Virtual function table. */ \
pjsip_hdr_vptr *vptr
3.3.3 Common Header Functions
pjsip_hdr_vptr指定virtual函数表,有每个header type来实现。表包含以下函数指针:
struct pjsip_hdr_vptr
{
pjsip_hdr *(*clone) ( pj_pool_t *pool, const pjsip_hdr *hdr );
pjsip_hdr *(*shallow_clone)( pj_pool_t *pool, const pjsip_hdr *hdr );
int (*print_on) ( pjsip_hdr *hdr, char *buf, pj_size_t len );
};
尽管应用程序可以自由的直接调用 pjsip_hdr_vptr的函数指针,还是建议使用下面的header API,因为可以让程序易读。
pjsip_hdr *pjsip_hdr_clone( pj_pool_t *pool,
const pjsip_hdr *hdr );
深度复制hdr header
pjsip_hdr *pjsip_hdr_shallow_clone( pj_pool_t *pool,
const pjsip_hdr *hdr );
浅克隆hdr header。浅克隆创建一个新的指定头字段的精准复制,但是很多值的指针依然还是指向原header。通常浅克隆就是从源header到新header的memcpy,因此推测它的操作快于深度克隆。
但是,浅克隆的时候需要仔细。必须明白新的header和旧header共用一个指针。所以,当池中旧的header被销毁,新的header也无效即使浅克隆的时候使用了不一样的内存池。或者是旧header的一些值被改了,相应的新header里的也会改变。
即使这样,浅克隆依然在库中广泛应用。比如,一个dialog一些头的值总是出现(比如 From, To, Call-Id, Route, and Contac)。当要创建一个请求,dialog浅克隆这个header(而不是全部复制)然后放到请求的消息中。
int pjsip_hdr_print_on( pjsip_hdr *hdr,
char *buf,
pj_size_t max_size);
将指定的header打印到缓冲区(比如传输前)。函数返回打印的字节数,如果溢出返回-1。
3.3.4 Supported Header Fields
<pjsip/sip_msg.h>定义PJSIP header的规范。其他的头字段可能定义在扩展规范里实现一个特定的功能或者SIP的扩展(比如header使用SIMPLE)。
每个头字段通常仅定义一个特定的API来操作他们,也就是创建特定头字段的函数。其他的API通过虚函数表导出。
创建每个头字段的API以头字段名后跟_create()来命名。比如,调用函数 pjsip_via_hdr_create()来创建 pjsip_via_hdr 实例。
参考<pjsip/sip_msg.h>中 PJSIP核心定义的完整头字段列表。
3.3.5 Header Array Elements
很多的sip header(比如 Require,Contact,via等)可以当成一组放在一起作为一个单独的头字段,以逗号分隔。如:
Contact: <sip:alice@sip.example.com>;q=1.0, <tel:+442081234567>;q=0.5
Via: SIP/2.0/UDP proxy1.example.com;branch=z9hG4bK87asdks7, SIP/2.0/UDP
proxy2.example.com;branch=z9hG4bK77asjd
NOTE:PJSIP不支持header里有复杂header type( Contact, Via, Route, Record-Route)的数组元素,但支持简单的字符串数组( Require,Supported)。
当解析器遇到上面这种组合的时候,就会把每个数组按照出现的顺序分成单独的header。所以就会被解析为以下的格式:
Contact: <sip:alice@sip.example.com>;q=1.0
Contact: <tel:+442081234567>;q=0.5
Via: SIP/2.0/UDP proxy1.example.com;branch=z9hG4bK87asdks7
Via: SIP/2.0/UDP proxy2.example.com;branch=z9hG4bK77asjd
SIP的规范指明在处理这种header描述方式的消息时不应该有任何区别。所以我们认为即使不支持头数组,功能也不会受到影响。
限制这个的原因就是根据经验,移除了头数组的确简化了header的处理。如果支持数组,应用程序不仅要检查所有的header,还要检查一些header里的数组。如果不支持头数组,应用程序只需要检查消息的主要头列表。
3.4 Message Body (pjsip_msg_body)
PJSIP的pjsip_msg_body结构体描述SIP消息体。结构体在<pjsip/sip_msg.h>里。
struct pjsip_msg_body
{
/** MIME content type.
* * For incoming messages, the parser will fill in this member with the
* * content type found in Content-Type header.
* *
* * For outgoing messages, application must fill in this member with
* * appropriate value, because the stack will generate Content-Type header
* * based on the value specified here.
* */
pjsip_media_type content_type;
/** Pointer to buffer which holds the message body data.
* * For incoming messages, the parser will fill in this member with the
* * pointer to the body string.
* *
* * When sending outgoing message, this member doesn't need to point to the
* * actual message body string. It can be assigned with arbitrary pointer,
* * because the value will only need to be understood by the print_body()
* * function. The stack itself will not try to interpret this value, but
* * instead will always call the print_body() whenever it needs to get the
* * actual body string.
* */
void *data;
/** The length of the data.
* * For incoming messages, the parser will fill in this member with the
* * actual length of message body.
* *
* * When sending outgoing message, again just like the "data" member, the
* * "len" member doesn't need to point to the actual length of the body
* * string.
* */
unsigned len;
/** Pointer to function to print this message body.
* * Application must set a proper function here when sending outgoing
* * message.
* *
* * @param msg_body This structure itself.
* * @param buf The buffer.
* * @param size The buffer size.
* *
* * @return The length of the string printed, or -1 if there is
* * not enough space in the buffer to print the whole
* * message body.
* */
int (*print_body) ( struct pjsip_msg_body *msg_body,
char *buf, pj_size_t size );
/** Pointer to function to clone the data in this message body.
* */
void* (*clone_data) ( pj_pool_t *pool, const void *data, unsigned len );
};
下面的API用来操作sip消息对象。
pj_status_t pjsip_msg_body_clone( pj_pool_t *pool,
pjsip_msg_body *dst_body,
const pjsip_msg_body *src_body);
将消息从src_body复制到dst_body。使用源消息体clone_data成员来复制消息体的正文。
3.5 Message (pjsip_msg)
PJSIP的请求和响应消息在结构体pjsip_msg里,头文件是<pjsip/sip_msg.h>。下面是一些代码段,pjsip_msg的描述以及其他支持的结构体。
enum pjsip_msg_type_e
{
PJSIP_REQUEST_MSG, // Indicates request message.
PJSIP_RESPONSE_MSG, // Indicates response message.
};
struct pjsip_request_line
{
pjsip_method method; // Method for this request line.
pjsip_uri *uri; // URI for this request line.
};
struct pjsip_status_line
{
int code; // Status code.
pj_str_t reason; // Reason string.
};
struct pjsip_msg
{
/** Message type (ie request or response). */
pjsip_msg_type_e type;
/** The first line of the message can be either request line for request
* * messages, or status line for response messages. It is represented here
* * as a union.
* */
union
{
/** Request Line. */
struct pjsip_request_line req;
/** Status Line. */
struct pjsip_status_line status;
} line;
/** List of message headers. */
pjsip_hdr hdr;
/** Pointer to message body, or NULL if no message body is attached to
* * this mesage.
* */
pjsip_msg_body *body;
};
下面的API用来操作sip消息对象。
pjsip_msg* pjsip_msg_create( pj_pool_t *pool,
pjsip_msg_type_e type);
根据type创建请求或响应消息。
pjsip_hdr* pjsip_msg_find_hdr( pjsip_msg *msg,
pjsip_hdr_e hdr_type,
pjsip_hdr *start);
在消息中从头列表的指定的start位置查找指定type的header。如果start是NULL,函数从消息的第一个header搜索。返回NULL说明在这位置后没有别的header。
pjsip_hdr* pjsip_msg_find_hdr_by_name( pjsip_msg *msg,
const pj_str_t *name,
pjsip_hdr *start);
在消息中从头列表指定start位置搜索header版本的长名和短名,根据指定的name查找header。如果start是NULL,函数从消息的第一个header查找。返回NULL说明这位置后没有别的header。
void pjsip_msg_add_hdr( pjsip_msg *msg,
pjsip_hdr *hdr);
在消息中加入hdr作为最后一个header。
void pjsip_msg_insert_first_hdr( pjsip_msg *msg,
pjsip_hdr *hdr);
在消息中加入hdr作为第一个header。
pj_ssize_t pjsip_msg_print( pjsip_msg *msg,
char *buf,
pj_size_t size );
打印这个消息正文到指定缓冲区。函数返回字节数,溢出返回-1。
3.6 SIP Status Codes
SIP规范(RFC3261)中定义的SIP状态码在pjsip_status_code枚举中,头文件<pjsip/sip_msg.h>。此外,可以通过调用 pjsip_get_status_text来获取缺省reason值。
下面的代码段描述了PJSIP的状态码。
enum pjsip_status_code
{
PJSIP_SC_TRYING = 100,
PJSIP_SC_RINGING = 180,
PJSIP_SC_CALL_BEING_FORWARDED = 181,
PJSIP_SC_QUEUED = 182,
PJSIP_SC_PROGRESS = 183,
PJSIP_SC_OK = 200,
PJSIP_SC_MULTIPLE_CHOICES = 300,
PJSIP_SC_MOVED_PERMANENTLY = 301,
PJSIP_SC_MOVED_TEMPORARILY = 302,
PJSIP_SC_USE_PROXY = 305,
PJSIP_SC_ALTERNATIVE_SERVICE = 380,
PJSIP_SC_BAD_REQUEST = 400,
PJSIP_SC_UNAUTHORIZED = 401,
?PJSIP_SC_PAYMENT_REQUIRED = 402,
PJSIP_SC_FORBIDDEN = 403,
PJSIP_SC_NOT_FOUND = 404,
PJSIP_SC_METHOD_NOT_ALLOWED = 405,
PJSIP_SC_NOT_ACCEPTABLE = 406,
PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407,
PJSIP_SC_REQUEST_TIMEOUT = 408,
PJSIP_SC_GONE = 410,
PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413,
PJSIP_SC_REQUEST_URI_TOO_LONG = 414,
PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415,
PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416,
PJSIP_SC_BAD_EXTENSION = 420,
PJSIP_SC_EXTENSION_REQUIRED = 421,
PJSIP_SC_INTERVAL_TOO_BRIEF = 423,
PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480,
PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481,
PJSIP_SC_LOOP_DETECTED = 482,
PJSIP_SC_TOO_MANY_HOPS = 483,
PJSIP_SC_ADDRESS_INCOMPLETE = 484,
PJSIP_AC_AMBIGUOUS = 485,
PJSIP_SC_BUSY_HERE = 486,
PJSIP_SC_REQUEST_TERMINATED = 487,
PJSIP_SC_NOT_ACCEPTABLE_HERE = 488,
PJSIP_SC_REQUEST_PENDING = 491,
PJSIP_SC_UNDECIPHERABLE = 493,
PJSIP_SC_INTERNAL_SERVER_ERROR = 500,
PJSIP_SC_NOT_IMPLEMENTED = 501,
PJSIP_SC_BAD_GATEWAY = 502,
PJSIP_SC_SERVICE_UNAVAILABLE = 503,
PJSIP_SC_SERVER_TIMEOUT = 504,
PJSIP_SC_VERSION_NOT_SUPPORTED = 505,
PJSIP_SC_MESSAGE_TOO_LARGE = 513,
PJSIP_SC_BUSY_EVERYWHERE = 600,
PJSIP_SC_DECLINE = 603,
PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604,
PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606,
PJSIP_SC_TSX_TIMEOUT = 701,
PJSIP_SC_TSX_RESOLVE_ERROR = 702,
PJSIP_SC_TSX_TRANSPORT_ERROR = 703,
};。
/* Get the default status text for the status code. */
const pj_str_t* pjsip_get_status_text(int status_code);
PJSIP可以定义消息处理过程(传输错误,DNS错误)中致命错误的错误码(7xx)类。这些类只能内部使用,不会传输到网络中。
3.7 Non-Standard Parameter Elements
在PJSIP中,已知的或者“标准”参数(URI参数,头字段参数)通常在相应的结构体中作为单独的属性或字段描述。非标准的参数将放入参数列表,每个参数为一个pjsip_param结构体。非标准参数通常在自己的结构体中声明为 other_para字段。
3.7.1 Data Structure Representation (pjsip_param)
下面的结构体描述了列表中的单独的参数。
struct pjsip_param
{
PJ_DECL_LIST_MEMBER(struct pjsip_param); // Generic list member.
pj_str_t name; // Param/header name.
pj_str_t value; // Param/header value.
};
举个例子, pjsip_sip_uri ( 3.1.4小节 “SIP and SIPS URI”)中的other_param和header_param字段描述或者 pjsip_tel_uri (3.1.5小节“Tel URI”)的other_param字段描述。
3.7.2 Non-Standard Parameter Manipulation
下面是用来操作参数表中非标准参数的函数。
pjsip_param* pjsip_param_find( const pjsip_param *param_list,
const pj_str_t *name );
不区分大小写来查找指定参数名
void pjsip_param_clone( pj_pool_t *pool,
pjsip_param *dst_list,
const pjsip_param *src_list);
参数列表的深(全)克隆。
void pjsip_param_shallow_clone( pj_pool_t *pool,
pjsip_param *dst_list,
const pjsip_param *src_list);
参数列表的浅克隆。
pj_ssize_t pjsip_param_print_on( const pjsip_param *param_list,
char *buf,
pj_size_t max_size,
const pj_cis_t *pname_unres,
const pj_cis_t *pvalue_unres,
int sep);
打印参数列表至指定的缓冲区。pname_unres和pvalue_unres分别是pname和pvalue的可允许出现未转义字符的规范;其他规范之外的字都会被转义。sep指的是参数之间的分割符(当参数列表是头参数的时候通常用;或,)。
3.8 Escapement Rules
PJSIP仅为以下消息元素在解析期间和打印期间支持自动反转义:
#URI的所有类型和元素根据单独的转义规则自动反转义或自动转义
#出现在所有消息元素(URL中的,或者头字段中的)中的参数自动转义或反转义。
其他的消息将在堆栈中直接(un-interpreted)传递。