Commit 12e094b2 authored by Pekka Pessi's avatar Pekka Pessi

sip: added Remote-Party-ID, P-Asserted-Identity, P-Preferred-Identity

Added functions sip_update_default_mclass() and sip_extend_mclass()
for handling the extended parser. Note that Reply-To and Alert-Info are only
available with the extended parser.

darcs-hash:20070919225959-65a35-6727d2eb6dd015e46ba88a556ca32a8e5c8e9369.gz
parent e7eedf86
Description of Adding a SIP Header to Sofia SIP
===============================================
Adding a SIP Header to Sofia SIP
================================
by Pekka Pessi (2002-08-16, updated 2006-10-03)
by Pekka Pessi (2002-08-16, last updated 2007-09-19)
There are three ways to extend the Sofia SIP parser, including a standard
header in sip_t structure, including a standard header in extra headers or
putting the extension headers into a separate library.
Probalem with extending #sip_t is that it breaks binary compatibility.
There are two recommended ways to extend the Sofia SIP parser, including a
standard header in extra headers or putting the extension headers into a
separate library.
In the text below, we use "Example" header as our example with following
ABNF:
......@@ -18,30 +16,18 @@ ABNF:
IF YOUR HEADER IS A STANDARD ONE
--------------------------------
* In <sip.h>, add:
* In <sofia-sip/sip_extra.h>, add:
- Add typedef to the header structure.
The typedefs to ordinary headers are in more or less alphabetic
order after typedef of sip_unknown_t. You should add a typedef line
like this:
You should add a typedef line like this:
typedef struct sip_example_s sip_example_t;
Note that the typedefs are documented together with the
implementation in the .c file.
- Add field to the sip_t structure (struct sip_s)
- Remember to add a comment containing the header name
after field for benefit of the AWK script autmatically generating
boilerplate functions and macros:
sip_example_t *sip_example; /**< Example */
- The AWK script msg_parser.awk automatically creates the default
prototypes and tags for the newly created header when the entry in
sip_t structure is formatted like to the example above.
It will complain about mismatches between header name and field name.
* Add the actual header structure:
- Add the actual header structure:
The header structure would look like below. The first field MUST be a
sip_common_t structure, second field MUST be a pointer to next header
......@@ -61,6 +47,21 @@ IF YOUR HEADER IS A STANDARD ONE
unsigned long ex_value; /**< Value of example. */
};
* Add entry to sip_extra_headers.txt:
- In this case:
example @NEW_2_0 /* Example header */
- The first is the base C name used for functions and types related to
the type. The AWK script msg_parser.awk automatically creates the
default prototypes and tags for the newly created header. It will
complain about mismatches between header name and the base name.
- If the entry is before #### DEFAULT HEADER LIST ENDS HERE ####
the new header is added to the default parser
- If after, the new header is added only to the extended parser.
- The extended parser will be used after call to
sip_update_default_mclass(NULL)
* Write parsing tests for your new headers in torture_sip.c:
Add all relevant parsing/processing cases you can think of
......@@ -86,8 +87,10 @@ IF YOUR HEADER IS A STANDARD ONE
* Run "make check" after you are ready. Really.
IF YOUR HEADERS ARE NON-STANDARD
--------------------------------
IF YOUR HEADERS ARE COMPLETELY NON-STANDARD
-------------------------------------------
* Add a separate library package for them
- There is an example package sofia-sip-2543.tar.gz, available from
sofia-sip.sourceforge.net
......@@ -147,6 +150,3 @@ struct sip_example_dummy_structure {
#endif /** !defined(SIP_EXAMPLE_H) */
--->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---->8---
......@@ -69,4 +69,6 @@ ALIASES += \
"ReplyTo=@ref sip_reply_to \"Reply-To\"" \
"SuppressBodyIfMatch=@ref sip_suppress_body_if_match \"Suppress-Body-If-Match\"" \
"SuppressNotifyIfMatch=@ref sip_suppress_notify_if_match \"Suppress-Notify-If-Match\"" \
"RemotePartyID=@ref sip_remote_party_id \"Remote-Party-ID\"" \
"PAssertedIdentity=@ref sip_p_asserted_identity \"P-Asserted-Identity\"" \
"PPreferredIdentity=@ref sip_p_preferred_identity \"P-Preferred-Identity\"" \
This diff is collapsed.
#
# This file specifies extra SIP headers not included in sip_t structure
#
# The parsed headers are accessed with function (or macro) like sip_refer_sub()
# e.g., sip_refer_sub_t *rsub = sip_refer_sub(sip);
#
# The line format is:
# C-name @SINCE sip_t-like-comment
#
......@@ -9,8 +12,19 @@
#### EXTRA HEADER LIST STARTS HERE ####
refer_sub @NEW_1_12_5 /**< Refer-Sub header */
#### DEFAULT HEADER LIST ENDS HERE ####
#
# These headers are added to the extended parser, installed
# as default with sip_update_default_mclass(NULL)
#
alert_info @NEW_1_12_7 /**< Alert-Info header */
reply_to @NEW_1_12_7 /**< Reply-To header */
remote_party_id @NEW_1_12_7 /**< Remote-Party-ID header */
p_asserted_identity @NEW_1_12_7 /**<P-Asserted-Identity*/
p_preferred_identity @NEW_1_12_7 /**<P-Preferred-Identity*/
#### EXPERIMENTAL HEADER LIST STARTS HERE ####
......
......@@ -60,11 +60,84 @@ char const sip_parser_version[] = VERSION;
char const sip_version_2_0[] = "SIP/2.0";
/** Default message class */
extern msg_mclass_t const sip_mclass[];
extern msg_mclass_t sip_mclass[];
static msg_mclass_t const *_default = sip_mclass;
/** Return a built-in SIP parser object. */
msg_mclass_t const *sip_default_mclass(void)
{
return sip_mclass;
return _default;
}
/** Update the default SIP parser.
*
* Use the extended SIP parser as default one.
*
* If the applications want to use headers added after @VERSION_1_12_5,
* they should call this function before doing any other initialization, e.g.,
* @code
* su_init();
* if (sip_update_default_mclass(sip_extend_mclass(NULL)) < 0) {
* su_deinit();
* exit(2);
* }
* @endcode
*
* The default parser is not extended because it may break the old
* applications looking for extension headers from sip_unknown list.
*
* @retval 0 when successful
* @retval -1 upon an error
*
* @NEW_1_12_7
*/
int sip_update_default_mclass(msg_mclass_t const *mclass)
{
if (mclass == NULL)
return -1;
_default = mclass;
return 0;
}
/**Extend SIP parser class with extension headers.
*
* Extend given SIP parser class with extension headers. If the given parser
* class is the default one or NULL, make a clone of it before extending it.
*
* @param input pointer to a SIP message class (may be NULL)
*
* @return Pointer to extended mclass, or NULL upon an error.
*
* @NEW_1_12_7
*/
msg_mclass_t *sip_extend_mclass(msg_mclass_t *input)
{
msg_mclass_t *mclass;
if (input == NULL || input == _default)
mclass = msg_mclass_clone(_default, 0, 0);
else
mclass = input;
if (mclass) {
extern msg_hclass_t const * const sip_extensions[];
int i;
for (i = 0; sip_extensions[i]; i++) {
msg_hclass_t const *hclass = sip_extensions[i];
if (mclass->mc_unknown != msg_find_hclass(mclass, hclass->hc_name, NULL))
continue;
if (msg_mclass_insert_header(mclass, hclass, 0) < 0) {
if (input != mclass)
free(mclass);
return mclass = NULL;
}
}
}
return mclass;
}
/** Extract the SIP message body, including separator line.
......
......@@ -1421,3 +1421,4 @@ int sip_response_terminates_dialog(int response_code,
return 0;
}
/**@file sofia-sip/sip_extra.h.in
`/**@file sofia-sip/sip_extra.h.in
* -*- C -*-
* Template for <sofia-sip/sip_extra.h>.
*
......@@ -117,6 +117,55 @@ struct sip_suppress_notify_if_match_s
char const *snim_tag; /**< Entity-tag */
};
typedef struct sip_p_asserted_identity_s sip_p_asserted_identity_t;
/**@ingroup sip_p_asserted_identity
* @brief Structure for @PAssertedIdentity header.
*/
struct sip_p_asserted_identity_s
{
sip_common_t paid_common[1];/**< Common fragment info */
sip_p_asserted_identity_t
*paid_next; /**< Link to next identity */
char const *paid_display; /**< Display name */
url_t paid_url[1]; /**< SIP, SIPS or TEL URL */
};
typedef struct sip_p_preferred_identity_s sip_p_preferred_identity_t;
/**@ingroup sip_p_preferred_identity
* @brief Structure for @PPreferredIdentity header.
*/
struct sip_p_preferred_identity_s
{
sip_common_t ppid_common[1];/**< Common fragment info */
sip_p_preferred_identity_t
*ppid_next; /**< Link to next identity */
char const *ppid_display; /**< Display name */
url_t ppid_url[1]; /**< SIP, SIPS or TEL URL */
};
int sip_p_initialize_remote_party_id_headers(msg_mclass_t *mclass);
typedef struct sip_remote_party_id_s sip_remote_party_id_t;
/**@ingroup sip_remote_party_id
* @brief Structure for @RemotePartyID header.
*/
struct sip_remote_party_id_s
{
sip_common_t rpid_common[1];/**< Common fragment info */
sip_remote_party_id_t
*rpid_next; /**< Link to next identity */
char const *rpid_display; /**< Display name */
url_t rpid_url[1]; /**< URL */
sip_param_t const *rpid_params; /**< Parameters */
/** Shortcuts to screen, party, id-type and privacy parameters */
char const *rpid_screen, *rpid_party, *rpid_id_type, *rpid_privacy;
};
/** Defined as 1 if the @ref sip_#xxxxxx# "#xxxxxxx_xxxxxxx#" is supported */
#define SIP_HAVE_#XXXXXX# 1
......
......@@ -57,13 +57,16 @@
SOFIA_BEGIN_DECLS
/** Return built-in SIP parser object. */
/** Return a built-in SIP parser object. */
SOFIAPUBFUN msg_mclass_t const *sip_default_mclass(void);
/** Check that sip_t is a SIP structure (not RTSP or HTTP). @HIDE */
SOFIAPUBFUN int sip_update_default_mclass(msg_mclass_t const *mclass);
SOFIAPUBFUN msg_mclass_t *sip_extend_mclass(msg_mclass_t *input);
/** Check that sip_t is a SIP header structure (not MIME or HTTP). @HIDE */
#define sip_is_sip(sip) ((sip) && (sip)->sip_ident == SIP_PROTOCOL_TAG)
/** Initializer for a SIP header object. @HIDE */
/** Initializer for a SIP header structure. @HIDE */
#define SIP_HDR_INIT(name) {{{ 0, 0, sip_##name##_class }}}
/** Initialize a SIP header structure. @HIDE */
......
......@@ -74,6 +74,135 @@ msg_mclass_t *test_mclass = NULL;
static msg_t *read_message(int flags, char const string[]);
static int test_identity(void)
{
su_home_t *home;
sip_p_asserted_identity_t *paid;
sip_p_preferred_identity_t *ppid;
msg_t *msg;
sip_t *sip;
BEGIN();
msg_href_t const *href;
msg_mclass_t const *def0, *def1, *ext;
def0 = sip_default_mclass();
/* Check that Refer-Sub has been added to our parser */
TEST_1(href = msg_find_hclass(def0, "Refer-Sub", NULL));
TEST_P(href->hr_class, sip_refer_sub_class);
/* Check that Reply-To is not there */
TEST_P(msg_find_hclass(def0, "Reply-To", NULL), def0->mc_unknown);
TEST_1(ext = sip_extend_mclass(NULL));
/* Update default parser */
TEST_1(sip_update_default_mclass(ext) == 0);
def1 = sip_default_mclass();
TEST_1(def0 != def1);
TEST_1(ext == def1);
TEST_1(href = msg_find_hclass(def1, "Reply-To", NULL));
TEST_P(href->hr_class, sip_reply_to_class);
TEST_1(test_mclass = msg_mclass_clone(def0, 0, 0));
msg = read_message(MSG_DO_EXTRACT_COPY,
"BYE sip:foo@bar SIP/2.0\r\n"
"To: <sip:foo@bar>;tag=deadbeef\r\n"
"From: <sip:bar@foo>;\r\n"
"Call-ID: 0ha0isndaksdj@10.1.2.3\r\n"
"CSeq: 8 SUBSCRIBE\r\n"
"Via: SIP/2.0/UDP 135.180.130.133\r\n"
"P-Asserted-Identity: <sip:test@test.domain.com>\r\n"
"P-Preferred-Identity: <sip:test@test.domain.com>, <tel:+358708008000>\r\n"
"Content-Length: 0\r\n"
"\r\n");
sip = sip_object(msg);
TEST_1(!sip_p_asserted_identity(sip));
TEST_1(!sip_p_preferred_identity(sip));
msg_destroy(msg);
TEST_1(msg_mclass_insert_header(test_mclass,
sip_p_asserted_identity_class, 0) > 0);
TEST_1(msg_mclass_insert_header(test_mclass,
sip_p_preferred_identity_class, 0) > 0);
msg = read_message(MSG_DO_EXTRACT_COPY,
"BYE sip:foo@bar SIP/2.0\r\n"
"To: <sip:foo@bar>;tag=deadbeef\r\n"
"From: <sip:bar@foo>;\r\n"
"Call-ID: 0ha0isndaksdj@10.1.2.3\r\n"
"CSeq: 8 SUBSCRIBE\r\n"
"Via: SIP/2.0/UDP 135.180.130.133\r\n"
"P-Asserted-Identity: <sip:test@test.domain.com>\r\n"
"P-Preferred-Identity: <sip:test@test.domain.com>, <tel:+358708008000>\r\n"
"Content-Length: 0\r\n"
"\r\n");
sip = sip_object(msg);
TEST_1(home = msg_home(msg));
TEST_1((paid = sip_p_asserted_identity_make(home, "sip:joe@example.com")));
TEST_1((paid = sip_p_asserted_identity_make
(home, "Jaska <sip:joe@example.com>, Helmi <tel:+3587808000>")));
TEST_1(paid->paid_next);
TEST_1((ppid = sip_p_preferred_identity_make(home, "sip:joe@example.com")));
TEST_1((ppid = sip_p_preferred_identity_make
(home, "Jaska <sip:joe@example.com>, Helmi <tel:+3587808000>")));
msg_destroy(msg);
/* Now with extensions */
TEST_1(test_mclass = msg_mclass_clone(def1, 0, 0));
{
su_home_t *home = su_home_clone(NULL, sizeof *home);
char *s;
char const canonic[] =
"\"Jaska Jokunen\" <sip:jaska.jokunen@example.com>;"
"screen=yes;party=called;id-type=user;privacy=\"name,uri-network\"";
char const canonic2[] =
"Jaska Jokunen <sip:jaska.jokunen@example.com>;"
"screen=yes;party=called;id-type=user;privacy=\"name,uri-network\"";
sip_remote_party_id_t *rpid, *d;
TEST_1(rpid = sip_remote_party_id_make(home, canonic));
TEST_S(rpid->rpid_display, "\"Jaska Jokunen\"");
TEST_S(rpid->rpid_url->url_user, "jaska.jokunen");
TEST_S(rpid->rpid_params[0], "screen=yes");
TEST_S(rpid->rpid_screen, "yes");
TEST_S(rpid->rpid_party, "called");
TEST_S(rpid->rpid_id_type, "user");
TEST_S(rpid->rpid_privacy, "\"name,uri-network\"");
TEST_1(s = sip_header_as_string(home, (void*)rpid));
TEST_S(s, canonic);
TEST_1(d = sip_remote_party_id_dup(home, rpid));
TEST_S(d->rpid_display, rpid->rpid_display);
TEST_S(d->rpid_params[0], rpid->rpid_params[0]);
TEST_1(rpid = sip_remote_party_id_make(home, canonic2));
TEST_S(rpid->rpid_display, "Jaska Jokunen");
TEST_1(s = sip_header_as_string(home, (void*)rpid));
TEST_S(s, canonic2);
TEST_1(d = sip_remote_party_id_dup(home, rpid));
TEST_S(d->rpid_display, rpid->rpid_display);
su_home_check(home);
su_home_zap(home);
}
END();
}
int test_url_headers(void)
{
BEGIN();
......@@ -2193,7 +2322,7 @@ int test_refer(void)
TEST_1(home = su_home_create());
/* Check that Refer-Sub has already been added to our parser */
/* Check that Refer-Sub has now been added to our parser */
TEST_1(msg_mclass_insert_with_mask(test_mclass, sip_refer_sub_class,
0, 0) == -1);
......@@ -3338,9 +3467,13 @@ int main(int argc, char *argv[])
tstflags |= tst_verbatim;
#endif
if (!test_mclass)
retval |= test_identity(); fflush(stdout);
if (test_mclass == NULL)
test_mclass = msg_mclass_clone(sip_default_mclass(), 0, 0);
retval |= parser_test(); fflush(stdout);
retval |= test_url_headers(); fflush(stdout);
retval |= test_manipulation(); fflush(stdout);
retval |= test_methods(); fflush(stdout);
......@@ -3352,7 +3485,7 @@ int main(int argc, char *argv[])
retval |= tag_test(); fflush(stdout);
retval |= parser_tag_test(); fflush(stdout);
retval |= response_phrase_test(); fflush(stdout);
retval |= parser_test(); fflush(stdout);
retval |= sip_header_test(); fflush(stdout);
retval |= test_bad_packet(); fflush(stdout);
retval |= test_sip_list_header(); fflush(stdout);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment