summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-01-30 18:40:05 +0000
committerBenny Prijono <bennylp@teluu.com>2006-01-30 18:40:05 +0000
commit0d61adeb5f784b45f76d76dad9974f4111fb3c8c (patch)
tree4fe8830715bd6af57dd91ebca780318a645435cd
parent7638eeee106fe58a1225f642e733629f29418818 (diff)
Finished implementation of UA layer (to be tested)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@127 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjlib/include/pj++/list.hpp30
-rw-r--r--pjlib/include/pj++/pool.hpp8
-rw-r--r--pjlib/include/pj++/string.hpp76
-rw-r--r--pjlib/include/pj++/types.hpp14
-rw-r--r--pjlib/include/pj/assert.h2
-rw-r--r--pjlib/include/pj/hash.h51
-rw-r--r--pjlib/src/pj/hash.c99
-rw-r--r--pjmedia/docs/PJMEDIA.txt11
-rw-r--r--pjsip/build/pjsip.dsw24
-rw-r--r--pjsip/build/pjsip_core.dsp144
-rw-r--r--pjsip/build/pjsip_ua.dsp25
-rw-r--r--pjsip/build/test_pjsip.dsp4
-rw-r--r--pjsip/include/pjsip-ua/sip_dialog.h635
-rw-r--r--pjsip/include/pjsip.h (renamed from pjsip/include/pjsip_core.h)40
-rw-r--r--pjsip/include/pjsip/sip_auth.h12
-rw-r--r--pjsip/include/pjsip/sip_config.h4
-rw-r--r--pjsip/include/pjsip/sip_dialog.h324
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h91
-rw-r--r--pjsip/include/pjsip/sip_errno.h16
-rw-r--r--pjsip/include/pjsip/sip_module.h11
-rw-r--r--pjsip/include/pjsip/sip_msg.h524
-rw-r--r--pjsip/include/pjsip/sip_transaction.h1
-rw-r--r--pjsip/include/pjsip/sip_transport.h8
-rw-r--r--pjsip/include/pjsip/sip_types.h17
-rw-r--r--pjsip/include/pjsip/sip_ua_layer.h (renamed from pjsip/include/pjsip-ua/sip_ua.h)45
-rw-r--r--pjsip/include/pjsip/sip_uri.h16
-rw-r--r--pjsip/src/pjsip-ua/sip_dialog.c1802
-rw-r--r--pjsip/src/pjsip-ua/sip_ua.c473
-rw-r--r--pjsip/src/pjsip/sip_auth_client.c36
-rw-r--r--pjsip/src/pjsip/sip_dialog.c1138
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c99
-rw-r--r--pjsip/src/pjsip/sip_errno.c6
-rw-r--r--pjsip/src/pjsip/sip_msg.c376
-rw-r--r--pjsip/src/pjsip/sip_parser.c16
-rw-r--r--pjsip/src/pjsip/sip_tel_uri.c12
-rw-r--r--pjsip/src/pjsip/sip_transaction.c38
-rw-r--r--pjsip/src/pjsip/sip_transport.c45
-rw-r--r--pjsip/src/pjsip/sip_ua_layer.c674
-rw-r--r--pjsip/src/pjsip/sip_uri.c38
-rw-r--r--pjsip/src/pjsip/sip_util.c10
-rw-r--r--pjsip/src/test-pjsip/dlg_core_test.c (renamed from pjsip/src/pjsip-ua/sip_ua_private.h)18
-rw-r--r--pjsip/src/test-pjsip/msg_logger.c4
-rw-r--r--pjsip/src/test-pjsip/msg_test.c45
-rw-r--r--pjsip/src/test-pjsip/test.c2
-rw-r--r--pjsip/src/test-pjsip/transport_loop_test.c2
-rw-r--r--pjsip/src/test-pjsip/transport_test.c6
-rw-r--r--pjsip/src/test-pjsip/transport_udp_test.c2
-rw-r--r--pjsip/src/test-pjsip/tsx_basic_test.c2
-rw-r--r--pjsip/src/test-pjsip/tsx_uac_test.c6
-rw-r--r--pjsip/src/test-pjsip/tsx_uas_test.c6
-rw-r--r--pjsip/src/test-pjsip/txdata_test.c2
-rw-r--r--pjsip/src/test-pjsip/uri_test.c38
-rw-r--r--svn_add6
53 files changed, 3751 insertions, 3383 deletions
diff --git a/pjlib/include/pj++/list.hpp b/pjlib/include/pj++/list.hpp
index 433bd512..456e87d2 100644
--- a/pjlib/include/pj++/list.hpp
+++ b/pjlib/include/pj++/list.hpp
@@ -63,7 +63,7 @@ public:
}
const_iterator operator++()
{
- return const_iterator(node_->next);
+ return const_iterator((const List_Node *)node_->next);
}
bool operator==(const const_iterator &rhs)
{
@@ -99,7 +99,7 @@ public:
}
iterator operator++()
{
- return iterator(node_->next);
+ return iterator((List_Node*)node_->next);
}
bool operator==(const iterator &rhs)
{
@@ -121,6 +121,30 @@ public:
}
//
+ // You can cast Pj_List to pj_list
+ //
+ operator pj_list&()
+ {
+ return (pj_list&)root_;
+ }
+ operator const pj_list&()
+ {
+ return (const pj_list&)root_;
+ }
+
+ //
+ // You can cast Pj_List to pj_list* too
+ //
+ operator pj_list*()
+ {
+ return (pj_list*)&root_;
+ }
+ operator const pj_list*()
+ {
+ return (const pj_list*)&root_;
+ }
+
+ //
// Check if list is empty.
//
bool empty() const
@@ -318,7 +342,7 @@ private:
// If you see error in this line,
// it's because List_Node is not derived from Pj_List_Node.
List_Node *n = (List_Node*)0;
- n = n->next; n = n->prev;
+ n = (List_Node *)n->next; n = (List_Node *)n->prev;
}
};
diff --git a/pjlib/include/pj++/pool.hpp b/pjlib/include/pj++/pool.hpp
index 02b54336..d2604142 100644
--- a/pjlib/include/pj++/pool.hpp
+++ b/pjlib/include/pj++/pool.hpp
@@ -123,6 +123,14 @@ public:
}
//
+ // You can cast Pj_Pool to pj_pool_t*
+ //
+ operator pj_pool_t*()
+ {
+ return p_;
+ }
+
+ //
// Get pjlib compatible pool object.
//
pj_pool_t *pool_()
diff --git a/pjlib/include/pj++/string.hpp b/pjlib/include/pj++/string.hpp
index 1c868986..e16132f5 100644
--- a/pjlib/include/pj++/string.hpp
+++ b/pjlib/include/pj++/string.hpp
@@ -40,9 +40,9 @@ public:
}
//
- // Construct the buffer from a char*.
+ // Construct the buffer from a char* (use with care)
//
- explicit Pj_String(char *str)
+ Pj_String(char *str)
{
set(str);
}
@@ -50,44 +50,55 @@ public:
//
// Construct from a const char*.
//
- Pj_String(Pj_Pool *pool, const char *src)
+ Pj_String(Pj_Pool &pool, const char *src)
{
set(pool, src);
}
//
- // Construct from pj_str_t*.
+ // Construct from pj_str_t&.
//
- explicit Pj_String(pj_str_t *s)
+ explicit Pj_String(pj_str_t &s)
{
- set(s);
+ ptr = s.ptr;
+ slen = s.slen;
}
//
- // Construct by copying from const pj_str_t*.
+ // Construct from const pj_str_t& (use with care!).
//
- Pj_String(Pj_Pool *pool, const pj_str_t *s)
+ explicit Pj_String(const pj_str_t &s)
{
- set(pool, s);
+ ptr = (char*)s.ptr;
+ slen = s.slen;
}
//
- // Construct from another Pj_String
+ // Construct by copying from const pj_str_t*.
//
- explicit Pj_String(Pj_String &rhs)
+ Pj_String(Pj_Pool &pool, const pj_str_t *s)
{
- set(rhs);
+ set(pool, s);
}
//
// Construct by copying from Pj_String
//
- Pj_String(Pj_Pool *pool, const Pj_String &rhs)
+ Pj_String(Pj_Pool &pool, const Pj_String &rhs)
{
set(pool, rhs);
}
//
+ // Construct from another Pj_String, use with care!
+ //
+ explicit Pj_String(const Pj_String &rhs)
+ {
+ ptr = rhs.ptr;
+ slen = rhs.slen;
+ }
+
+ //
// Construct from a char* and a length.
//
Pj_String(char *str, pj_size_t len)
@@ -104,6 +115,22 @@ public:
}
//
+ // You can cast Pj_String to pj_str_t*
+ //
+ operator pj_str_t*()
+ {
+ return this;
+ }
+
+ //
+ // You can cast const Pj_String to const pj_str_t*
+ //
+ operator const pj_str_t*() const
+ {
+ return this;
+ }
+
+ //
// Get the length of the string.
//
pj_size_t length() const
@@ -138,9 +165,9 @@ public:
//
// Initialize by copying from a const char*.
//
- void set(Pj_Pool *pool, const char *s)
+ void set(Pj_Pool &pool, const char *s)
{
- pj_strdup2(pool->pool_(), this, s);
+ pj_strdup2(pool, this, s);
}
//
@@ -154,9 +181,9 @@ public:
//
// Initialize by copying from const pj_str_t*.
//
- void set(Pj_Pool *pool, const pj_str_t *s)
+ void set(Pj_Pool &pool, const pj_str_t *s)
{
- pj_strdup(pool->pool_(), this, s);
+ pj_strdup(pool, this, s);
}
//
@@ -186,17 +213,17 @@ public:
//
// Initialize by copying from a Pj_String*.
//
- void set(Pj_Pool *pool, const Pj_String *s)
+ void set(Pj_Pool &pool, const Pj_String *s)
{
- pj_strdup(pool->pool_(), this, s);
+ pj_strdup(pool, this, s);
}
//
// Initialize by copying from other Pj_String.
//
- void set(Pj_Pool *pool, const Pj_String &s)
+ void set(Pj_Pool &pool, const Pj_String &s)
{
- pj_strdup(pool->pool_(), this, &s);
+ pj_strdup(pool, this, &s);
}
//
@@ -353,11 +380,12 @@ public:
}
///
- // Assign from another Pj_String
+ // Assign from another Pj_String, use with care!
//
- Pj_String& operator=(Pj_String &rhs)
+ Pj_String& operator=(const Pj_String &rhs)
{
- set(rhs);
+ ptr = rhs.ptr;
+ slen = rhs.slen;
return *this;
}
diff --git a/pjlib/include/pj++/types.hpp b/pjlib/include/pj++/types.hpp
index e0c2e230..7e165a53 100644
--- a/pjlib/include/pj++/types.hpp
+++ b/pjlib/include/pj++/types.hpp
@@ -156,5 +156,19 @@ private:
};
+//
+// Macro to declare common object comparison operators.
+//
+#define PJ_DECLARE_OPERATORS(rhs_type) \
+ bool operator!=(rhs_type rhs) const { \
+ return !operator==(rhs); } \
+ bool operator<=(rhs_type rhs) const { \
+ return operator<(rhs) || operator==(rhs); } \
+ bool operator>(rhs_type rhs) const { \
+ return !operator<=(rhs); } \
+ bool operator>=(rhs_type rhs) const { \
+ return !operator<(rhs); }
+
+
#endif /* __PJPP_TYPES_HPP__ */
diff --git a/pjlib/include/pj/assert.h b/pjlib/include/pj/assert.h
index 6814e4cd..d6cb5163 100644
--- a/pjlib/include/pj/assert.h
+++ b/pjlib/include/pj/assert.h
@@ -49,7 +49,7 @@
/**
* @hideinitializer
- * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then
+ * If #PJ_ENABLE_EXTRA_CHECK is declared and the value is non-zero, then
* #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during
* run-time. If the expression yields false, assertion will be triggered
* and the current function will return with the specified return value.
diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h
index 41c89bc0..091c82b6 100644
--- a/pjlib/include/pj/hash.h
+++ b/pjlib/include/pj/hash.h
@@ -45,6 +45,11 @@ PJ_BEGIN_DECL
#define PJ_HASH_KEY_STRING ((unsigned)-1)
/**
+ * This indicates the size of of each hash entry.
+ */
+#define PJ_HASH_ENTRY_SIZE (3*sizeof(void*) + 2*sizeof(pj_uint32_t))
+
+/**
* This is the function that is used by the hash table to calculate hash value
* of the specified key.
*
@@ -92,15 +97,24 @@ PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);
* @param key the key to look for.
* @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
* string length of the key.
+ * @param hval if this argument is not NULL and the value is not zero,
+ * the value will be used as the computed hash value. If
+ * the argument is not NULL and the value is zero, it will
+ * be filled with the computed hash upon return.
*
* @return the value associated with the key, or NULL if the key is not found.
*/
PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
- const void *key, unsigned keylen );
+ const void *key, unsigned keylen,
+ pj_uint32_t *hval );
/**
- * Associate/disassociate a value with the specified key.
+ * Associate/disassociate a value with the specified key. If value is not
+ * NULL and entry already exists, the entry's value will be overwritten.
+ * If value is not NULL and entry does not exist, a new one will be created
+ * with the specified pool. Otherwise if value is NULL, entry will be
+ * deleted if it exists.
*
* @param pool the pool to allocate the new entry if a new entry has to be
* created.
@@ -108,13 +122,44 @@ PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
* @param key the key.
* @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
* string length of the key.
+ * @param hval if the value is not zero, then the hash table will use
+ * this value to search the entry's index, otherwise it will
+ * compute the key. This value can be obtained when calling
+ * #pj_hash_get().
* @param value value to be associated, or NULL to delete the entry with
* the specified key.
*/
PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
- const void *key, unsigned keylen,
+ const void *key, unsigned keylen, pj_uint32_t hval,
void *value );
+
+/**
+ * Associate/disassociate a value with the specified key. This function works
+ * like #pj_hash_set(), except that it doesn't use pool (hence the np -- no
+ * pool suffix). If new entry needs to be allocated, it will use the entry_buf.
+ *
+ * @param ht the hash table.
+ * @param key the key.
+ * @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
+ * string length of the key.
+ * @param hval if the value is not zero, then the hash table will use
+ * this value to search the entry's index, otherwise it will
+ * compute the key. This value can be obtained when calling
+ * #pj_hash_get().
+ * @param entry_buf Pointer to buffer which will be used for the new entry,
+ * when one needs to be created. The buffer must be at least
+ * PJ_HASH_ENTRY_SIZE long, and the first PJ_HASH_ENTRY_SIZE
+ * bytes of the buffer will be used by the hash table.
+ * Application may use the remaining portion of the buffer
+ * for its own purpose.
+ * @param value value to be associated, or NULL to delete the entry with
+ * the specified key.
+ */
+PJ_DECL(void) pj_hash_set_np(pj_hash_table_t *ht,
+ const void *key, unsigned keylen,
+ pj_uint32_t hval, void *entry_buf, void *value);
+
/**
* Get the total number of entries in the hash table.
*
diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index 739f2757..0495fadc 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -22,6 +22,7 @@
#include <pj/pool.h>
#include <pj/os.h>
#include <pj/ctype.h>
+#include <pj/assert.h>
/**
* The hash multiplier used to calculate hash value.
@@ -57,7 +58,6 @@ PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned key
for ( ; *p; ++p ) {
hash = hash * PJ_HASH_MULTIPLIER + *p;
}
- keylen = p - (const unsigned char*)key;
} else {
const unsigned char *p = key,
*end = p + keylen;
@@ -88,6 +88,9 @@ PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
pj_hash_table_t *h;
unsigned table_size;
+ /* Check that PJ_HASH_ENTRY_SIZE is correct. */
+ PJ_ASSERT_RETURN(sizeof(pj_hash_entry)==PJ_HASH_ENTRY_SIZE, NULL);
+
h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
h->count = 0;
@@ -110,24 +113,36 @@ PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
const void *key, unsigned keylen,
- void *val)
+ void *val, pj_uint32_t *hval,
+ void *entry_buf)
{
pj_uint32_t hash;
pj_hash_entry **p_entry, *entry;
- hash=0;
- if (keylen==PJ_HASH_KEY_STRING) {
- const unsigned char *p = key;
- for ( ; *p; ++p ) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
- }
- keylen = p - (const unsigned char*)key;
+ if (hval && *hval != 0) {
+ hash = *hval;
} else {
- const unsigned char *p = key,
- *end = p + keylen;
- for ( ; p!=end; ++p) {
- hash = hash * PJ_HASH_MULTIPLIER + *p;
+ /* This slightly differs with pj_hash_calc() because we need
+ * to get the keylen when keylen is PJ_HASH_KEY_STRING.
+ */
+ hash=0;
+ if (keylen==PJ_HASH_KEY_STRING) {
+ const unsigned char *p = key;
+ for ( ; *p; ++p ) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
+ keylen = p - (const unsigned char*)key;
+ } else {
+ const unsigned char *p = key,
+ *end = p + keylen;
+ for ( ; p!=end; ++p) {
+ hash = hash * PJ_HASH_MULTIPLIER + *p;
+ }
}
+
+ /* Report back the computed hash. */
+ if (hval)
+ *hval = hash;
}
/* scan the linked list */
@@ -136,7 +151,7 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
p_entry = &entry->next, entry = *p_entry)
{
if (entry->hash==hash && entry->keylen==keylen &&
- memcmp(entry->key, key, keylen)==0)
+ pj_memcmp(entry->key, key, keylen)==0)
{
break;
}
@@ -145,10 +160,21 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
if (entry || val==NULL)
return p_entry;
- /* create a new entry */
- entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
- PJ_LOG(6, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry,
- pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
+ /* Entry not found, create a new one.
+ * If entry_buf is specified, use it. Otherwise allocate from pool.
+ */
+ if (entry_buf) {
+ entry = entry_buf;
+ } else {
+ /* Pool must be specified! */
+ PJ_ASSERT_RETURN(pool != NULL, NULL);
+
+ entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
+ PJ_LOG(6, ("hashtbl",
+ "%p: New p_entry %p created, pool used=%u, cap=%u",
+ ht, entry, pj_pool_get_used_size(pool),
+ pj_pool_get_capacity(pool)));
+ }
entry->next = NULL;
entry->hash = hash;
entry->key = key;
@@ -162,20 +188,46 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
}
PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
- const void *key, unsigned keylen )
+ const void *key, unsigned keylen,
+ pj_uint32_t *hval)
{
pj_hash_entry *entry;
- entry = *find_entry( NULL, ht, key, keylen, NULL);
+
+ if (hval) *hval = 0;
+ entry = *find_entry( NULL, ht, key, keylen, NULL, hval, NULL);
return entry ? entry->value : NULL;
}
PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
- const void *key, unsigned keylen,
+ const void *key, unsigned keylen, pj_uint32_t hval,
void *value )
{
pj_hash_entry **p_entry;
- p_entry = find_entry( pool, ht, key, keylen, value );
+ p_entry = find_entry( pool, ht, key, keylen, value, &hval, NULL);
+ if (*p_entry) {
+ if (value == NULL) {
+ /* delete entry */
+ PJ_LOG(6, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
+ *p_entry = (*p_entry)->next;
+ --ht->count;
+
+ } else {
+ /* overwrite */
+ (*p_entry)->value = value;
+ PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht,
+ *p_entry, value));
+ }
+ }
+}
+
+PJ_DEF(void) pj_hash_set_np( pj_hash_table_t *ht,
+ const void *key, unsigned keylen,
+ pj_uint32_t hval, void *entry_buf, void *value)
+{
+ pj_hash_entry **p_entry;
+
+ p_entry = find_entry( NULL, ht, key, keylen, value, &hval, entry_buf );
if (*p_entry) {
if (value == NULL) {
/* delete entry */
@@ -186,7 +238,8 @@ PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
} else {
/* overwrite */
(*p_entry)->value = value;
- PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
+ PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht,
+ *p_entry, value));
}
}
}
diff --git a/pjmedia/docs/PJMEDIA.txt b/pjmedia/docs/PJMEDIA.txt
new file mode 100644
index 00000000..8d6a9105
--- /dev/null
+++ b/pjmedia/docs/PJMEDIA.txt
@@ -0,0 +1,11 @@
+The way PJMEDIA works at the moment is, for each destination party (e.g. remote INVITE party), we have one media "session". For each "m" line in the SDP, PJMEDIA creates one media "stream". If the stream is a bi-directional audio, then for each stream, two media "channels" will be created, so one media channel for each direction.
+
+The two channels in one stream share one instance of "codec". A codec is simple struct that provides encode() and decode() functions.
+
+The media channels will end up in the appropriate "sound stream". The decoder channel (i.e. RTP receiver) will end up in sound player stream, and the encoder channel (i.e. RTP sender) gets the audio frames from sound recorder stream.
+
+Both sound player and recorder devices (or streams) are active objects (they have their own threads). The media channel only needs to register callback function to be called when audio frames are available (or should be supplied) from/to the sound devices. This approach works very well with DirectSound, or with PortAudio's sound framework.
+
+But with the introduction of jitter buffer, another thread needs to be created for the decoder channel. The thread reads RTP from socket on a periodic basis, and put the frame (still encoded) to jitter buffer. When the sound player callback is called (by sound device), it looks for frame in the jitter buffer (instead of reading RTP socket), decode the frame, and return the PCM frame to the sound player.
+
+Now getting back to the topic why I think this could work as it is for your application. \ No newline at end of file
diff --git a/pjsip/build/pjsip.dsw b/pjsip/build/pjsip.dsw
index 5e6dfe03..00310dc7 100644
--- a/pjsip/build/pjsip.dsw
+++ b/pjsip/build/pjsip.dsw
@@ -15,6 +15,18 @@ Package=<4>
###############################################################################
+Project: "pjlib++"="..\..\pjlib\build\pjlib++.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
Project: "pjlib_util"="..\..\pjlib-util\build\pjlib_util.dsp" - Package Owner=<4>
Package=<5>
@@ -39,6 +51,18 @@ Package=<4>
###############################################################################
+Project: "pjsip++"=".\pjsip++.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
Project: "pjsip_core"=.\pjsip_core.dsp - Package Owner=<4>
Package=<5>
diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp
index 9a283221..30299861 100644
--- a/pjsip/build/pjsip_core.dsp
+++ b/pjsip/build/pjsip_core.dsp
@@ -85,73 +85,96 @@ LIB32=link.exe -lib
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Group "Base (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_client.c
+SOURCE=..\src\pjsip\sip_errno.c
# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_msg.c
+SOURCE=..\src\pjsip\sip_msg.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_parser.c
+SOURCE=..\src\pjsip\sip_parser.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_auth_server.c
+SOURCE=..\src\pjsip\sip_tel_uri.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_endpoint.c
+SOURCE=..\src\pjsip\sip_uri.c
# End Source File
+# End Group
+# Begin Group "Core (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_errno.c
+SOURCE=..\src\pjsip\sip_endpoint.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_msg.c
+SOURCE=..\src\pjsip\sip_util.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_parser.c
+SOURCE=..\src\pjsip\sip_util_proxy.c
# End Source File
+# End Group
+# Begin Group "Transport Layer (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
SOURCE=..\src\pjsip\sip_resolve.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_tel_uri.c
+SOURCE=..\src\pjsip\sip_transport.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transaction.c
+SOURCE=..\src\pjsip\sip_transport_loop.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport.c
+SOURCE=..\src\pjsip\sip_transport_udp.c
# End Source File
+# End Group
+# Begin Group "Authentication (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport_loop.c
+SOURCE=..\src\pjsip\sip_auth_client.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_transport_udp.c
+SOURCE=..\src\pjsip\sip_auth_msg.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_uri.c
+SOURCE=..\src\pjsip\sip_auth_parser.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjsip\sip_util.c
+SOURCE=..\src\pjsip\sip_auth_server.c
# End Source File
+# End Group
+# Begin Group "Transaction Layer (.c)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\src\pjsip\sip_util_proxy.c
+SOURCE=..\src\pjsip\sip_transaction.c
# End Source File
# Begin Source File
@@ -159,40 +182,72 @@ SOURCE=..\src\pjsip\sip_util_statefull.c
# PROP Exclude_From_Build 1
# End Source File
# End Group
+# Begin Group "UA Layer (.c)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_dialog.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\pjsip\sip_ua_layer.c
+# End Source File
+# End Group
+# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Group "Base Types (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_config.h
+# End Source File
# Begin Source File
-SOURCE=..\include\pjsip_core.h
+SOURCE=..\include\pjsip\sip_errno.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\print_util.h
+SOURCE=..\include\pjsip\sip_private.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth.h
+SOURCE=..\include\pjsip\sip_types.h
# End Source File
+# End Group
+# Begin Group "Messaging and Parsing (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth_msg.h
+SOURCE=..\include\pjsip\print_util.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_auth_parser.h
+SOURCE=..\include\pjsip\sip_msg.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_config.h
+SOURCE=..\include\pjsip\sip_parser.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_endpoint.h
+SOURCE=..\include\pjsip\sip_tel_uri.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_errno.h
+SOURCE=..\include\pjsip\sip_uri.h
+# End Source File
+# End Group
+# Begin Group "Core (.h)"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\pjsip\sip_endpoint.h
# End Source File
# Begin Source File
@@ -204,51 +259,68 @@ SOURCE=..\include\pjsip\sip_module.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_msg.h
+SOURCE=..\include\pjsip\sip_util.h
# End Source File
+# End Group
+# Begin Group "Transport Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_parser.h
+SOURCE=..\include\pjsip\sip_resolve.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_private.h
+SOURCE=..\include\pjsip\sip_transport.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_resolve.h
+SOURCE=..\include\pjsip\sip_transport_loop.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_tel_uri.h
+SOURCE=..\include\pjsip\sip_transport_udp.h
# End Source File
+# End Group
+# Begin Group "Authentication (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_transaction.h
+SOURCE=..\include\pjsip\sip_auth.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport.h
+SOURCE=..\include\pjsip\sip_auth_msg.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport_loop.h
+SOURCE=..\include\pjsip\sip_auth_parser.h
# End Source File
+# End Group
+# Begin Group "Transaction Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_transport_udp.h
+SOURCE=..\include\pjsip\sip_transaction.h
# End Source File
+# End Group
+# Begin Group "UA Layer (.h)"
+
+# PROP Default_Filter ""
# Begin Source File
-SOURCE=..\include\pjsip\sip_types.h
+SOURCE=..\include\pjsip\sip_dialog.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjsip\sip_uri.h
+SOURCE=..\include\pjsip\sip_ua_layer.h
# End Source File
+# End Group
# Begin Source File
-SOURCE=..\include\pjsip\sip_util.h
+SOURCE=..\include\pjsip.h
# End Source File
# End Group
# Begin Group "Inline Files"
diff --git a/pjsip/build/pjsip_ua.dsp b/pjsip/build/pjsip_ua.dsp
index 4d7ae9e5..c5986076 100644
--- a/pjsip/build/pjsip_ua.dsp
+++ b/pjsip/build/pjsip_ua.dsp
@@ -87,19 +87,16 @@ LIB32=link.exe -lib
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
-SOURCE="..\src\pjsip-ua\sip_dialog.c"
-# End Source File
-# Begin Source File
-
SOURCE="..\src\pjsip-ua\sip_reg.c"
-# End Source File
-# Begin Source File
-SOURCE="..\src\pjsip-ua\sip_ua.c"
-# End Source File
-# Begin Source File
+!IF "$(CFG)" == "pjsip_ua - Win32 Release"
+
+!ELSEIF "$(CFG)" == "pjsip_ua - Win32 Debug"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
-SOURCE="..\src\pjsip-ua\sip_ua_private.h"
# End Source File
# End Group
# Begin Group "Header Files"
@@ -107,16 +104,8 @@ SOURCE="..\src\pjsip-ua\sip_ua_private.h"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
-SOURCE="..\include\pjsip-ua\sip_dialog.h"
-# End Source File
-# Begin Source File
-
SOURCE="..\include\pjsip-ua\sip_regc.h"
# End Source File
-# Begin Source File
-
-SOURCE="..\include\pjsip-ua\sip_ua.h"
-# End Source File
# End Group
# End Target
# End Project
diff --git a/pjsip/build/test_pjsip.dsp b/pjsip/build/test_pjsip.dsp
index d890d9d5..306cb30b 100644
--- a/pjsip/build/test_pjsip.dsp
+++ b/pjsip/build/test_pjsip.dsp
@@ -89,6 +89,10 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
+SOURCE="..\src\test-pjsip\dlg_core_test.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\src\test-pjsip\main.c"
# End Source File
# Begin Source File
diff --git a/pjsip/include/pjsip-ua/sip_dialog.h b/pjsip/include/pjsip-ua/sip_dialog.h
deleted file mode 100644
index d46e3873..00000000
--- a/pjsip/include/pjsip-ua/sip_dialog.h
+++ /dev/null
@@ -1,635 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __PJSIP_DIALOG_H__
-#define __PJSIP_DIALOG_H__
-
-/**
- * @file dialog.h
- * @brief SIP Dialog abstraction
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_auth.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA_DIALOG SIP Dialog
- * @ingroup PJSUA
- * @{
- * \brief
- * This file contains SIP dialog, a higher level abstraction of SIP session.
- *
- * \par Overview
- * A SIP dialog is an abstraction of communication session between two user
- * agents that persist for some time. The dialog facilitates sequencing of
- * messages between the user agents and proper routing of requests between both
- * of them. The dialog represents a context in which to interpret SIP messages.
- * However method independent User Agent processing for requests and responses
- * outside of a dialog exists, hence a dialog is not necessary for message
- * processing.
- *
- * A dialog is identified at each User Agent with a dialog Id, which consists
- * of a Call-Id value, a local tag and a remote tag.
- *
- * A dialog contains certain pieces of data needed for further message
- * transmissions within the dialog. This data consists of:
- * - Dialog Id - used to identify the dialog.
- * - Local sequence number - used to order requests from the UA to its peer.
- * - Remote sequence number - used to order requests from its peer to the UA.
- * - Local URI - the address of the local party.
- * - Remote URI - the address of the remote party.
- * - Remote target - the address from the Contact header field of the request
- * or response or refresh request or response.
- * - "secure" boolean - determines if the dialog is secure.
- * - Route set - an ordered list of URIs. The route set is the list of servers
- * that need to be traversed to send a request to the peer.
- * - Authentication info - array of authentication credentials to be used
- * by the dialog to authenticate to proxies and servers.
- *
- * \par Manipulating Dialog
- * Application should use functions declared in this file to do something with
- * the dialog. Among other things, application can:
- * - create outgoing dialog (#pjsip_dlg_init()).
- * - sends outgoing invitation (#pjsip_dlg_invite()).
- * - sends response (provisional and final) to incoming invitation
- * (#pjsip_dlg_answer())
- * - disconnect dialog (#pjsip_dlg_disconnect()).
- * - send other request (#pjsip_dlg_create_request() and #pjsip_dlg_send_msg())
- *
- * \par Getting Dialog's Notification
- * Dialog emits notification about various things that's happening to it (e.g.
- * a message is received, dialog state has changed, etc.). Normally it is in
- * the interest of the application to capture these notifications, by
- * supplying the function to be called when the event occurs in #pjsip_dlg_callback
- * structure, and register this structure to user agent by calling
- * #pjsip_ua_set_dialog_callback().
- *
- * \par Incoming Invitation
- * Upon receiving a new incoming invitation, user agent will automatically create
- * a new dialog, and inform application via \b pjsip_dlg_callback.
- */
-
-/** Forward declaration for user agent structure. */
-typedef struct pjsip_user_agent pjsip_user_agent;
-
-/** Forward declaration for dialog structure. */
-typedef struct pjsip_dlg pjsip_dlg;
-
-/**
- * \brief Type of events that are reported by the dialog to the application callback
- * function.
- */
-typedef enum pjsip_dlg_event_e
-{
- /** Dialog state has changed. */
- PJSIP_DIALOG_EVENT_STATE_CHANGED,
-
- /** Any mid-call messages (reinvitation, message, etc.). */
- PJSIP_DIALOG_EVENT_MID_CALL_REQUEST,
-
- /** Other events (low level events). */
- PJSIP_DIALOG_EVENT_OTHER,
-
-} pjsip_dlg_event_e;
-
-
-/**
- * \brief Structure registered by applications to receive dialog notifications
- * from the User Agent.
- *
- * Applications registers this structure to get notifications from the User Agent
- * about dialog state changes and other events. Application can set any of
- * the callback function to NULL if it doesn't want to handle the notification,
- * however, setting some callbacks to NULL probably will cause some undesired
- * result (such as setting \b on_incoming to NULL will cause the creation of
- * a lot of dialogs with no owner).
- */
-struct pjsip_dlg_callback
-{
- /**
- * This is a low level, uninterpreted callback that is called by framework
- * for all kinds of events, such as transaction events, dialog events, etc.
- * @param dlg The dialog.
- * @param dlg_event The type of dialog event.
- * @param event The event descriptor.
- */
- void (*on_all_events)(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
- pjsip_event *event );
-
- /**
- * This is a low level callback that is called by the framework when the
- * underlying transaction is about to send outgoing message. This callback
- * is provided to allow application to modify the message before it is
- * transmitted.
- * @param dlg The dialog.
- * @param tsx The transaction that transmits the message.
- * @param tdata The transmission data, which contains the message.
- * @param retransmission The number of times this message has been sent.
- * Zero indicates the message is about to be sent the first time,
- * one indicates this is the first retransmission, etc.
- */
- void (*on_before_tx)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata, pj_bool_t retransmission);
-
- /**
- * This is a low level callback that is called by the framework when the dialog
- * has sent a message. Note that a receive of retransmission will not trigger
- * this callback since retransmission is handled internally by transaction.
- * @param dlg The dialog.
- * @param tsx The transaction that transmits the message.
- * @param tdata The transmission data, which contains the message.
- */
- void (*on_tx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata);
-
- /**
- * This is a low level callback that is called by the framework when the
- * dialog has received a message. Note that a receipt of retransmission
- * will not trigger this callback since retransmission is handled internally
- * by transaction.
- * @param dlg The dialog.
- * @param tsx The transaction that receives the message.
- * @param rdata The receive data, which contains the message.
- */
- void (*on_rx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_rx_data *rdata);
-
- /**
- * This callback is called by the framework when the user agent
- * instance receives an incoming INVITE message.
- * @param dlg The new dialog that's just created to handle the incoming call.
- * @param tsx The INVITE transaction that's just created.
- * @param rdata The receive data, which contains the INVITE message.
- */
- void (*on_incoming)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_rx_data *rdata);
-
- /**
- * This callback is called by the framework when the dialog is sending
- * the first outgoing INVITE message.
- * @param dlg The dialog.
- * @param tsx The INVITE transaction.
- * @param tdata The transmit data, which contains the INVITE message.
- */
- void (*on_calling)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_tx_data *tdata);
-
- /**
- * This callback is called by the framework when the initial INVITE
- * transaction has sent/received provisional response.
- * @param dlg The dialog.
- * @param tsx The transaction.
- * @param event The event, which src_type will always be either
- * PJSIP_EVENT_RX_MSG or PJSIP_EVENT_TX_MSG. The provisional
- * response message itself will be in either \b rdata or \b tdata.
- * @see pjsip_event.
- */
- void (*on_provisional)(pjsip_dlg *dlg, pjsip_transaction *tsx,
- pjsip_event *event);
-
- /**
- * This callback is called for both UAS and UAC dialog when 200 response
- * to INVITE is sent or received.
- * @param dlg The dialog.
- * @param event The event, which src_type can only be either
- * PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
- * @see pjsip_event
- */
- void (*on_connecting)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called for both UAS and UAC when an ACK request is
- * sent or received by the dialog.
- * @param dlg The dialog.
- * @param event The event, which src_type can only be either
- * PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
- * @see pjsip_event
- */
- void (*on_established)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called when the dialog is disconnected, i.e. upon
- * sending/receiving non-200 response to INVITE, sending/receiving
- * CANCEL to initial INVITE, and sending/receiving BYE.
- *
- * @param dlg The dialog.
- * @param event The event.
- * @see pjsip_event
- */
- void (*on_disconnected)(pjsip_dlg *dlg, pjsip_event *event);
-
- /**
- * This callback is called when the dialog is about to be destroyed.
- * @param dlg The dialog.
- */
- void (*on_terminated)(pjsip_dlg *dlg);
-
- /**
- * This callback will be called when the dialog receives mid call events
- * such as re-invitation or incoming pager.
- *
- * @param dlg The dialog.
- * @param event The event.
- */
- void (*on_mid_call_events)(pjsip_dlg *dlg, pjsip_event *event);
-
-}; /* struct pjsip_dlg_callback */
-
-
-
-/**
- * Dialog state.
- */
-typedef enum pjsip_dlg_state_e
-{
- /**
- * State NULL is after the dialog is instantiated but before any
- * initialization is done.
- */
- PJSIP_DIALOG_STATE_NULL,
-
- /**
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
- PJSIP_DIALOG_STATE_INCOMING,
-
- /**
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
- PJSIP_DIALOG_STATE_CALLING,
-
- /**
- * State PROCEEDING is after the dialog sent/received provisional
- * responses, but before final response is sent/received.
- */
- PJSIP_DIALOG_STATE_PROCEEDING,
-
- /**
- * State CONNECTING is after the dialog has sent/received final response
- * to the invitation, but before acknowledgement is sent.
- */
- PJSIP_DIALOG_STATE_CONNECTING,
-
- /**
- * State ESTABLISHED occurs after the invitation has been accepted and
- * acknowledged.
- */
- PJSIP_DIALOG_STATE_ESTABLISHED,
-
- /**
- * State DISCONNECTED occurs after either party successfully disconnect
- * the session.
- */
- PJSIP_DIALOG_STATE_DISCONNECTED,
-
- /**
- * State TERMINATE occurs when the dialog is ready to be destroyed.
- */
- PJSIP_DIALOG_STATE_TERMINATED,
-
-} pjsip_dlg_state_e;
-
-
-/**
- * Get the dialog string state.
- *
- * @param state Dialog state.
- * @return The string describing the state.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state);
-
-/**
- * This structure is used to describe dialog's participants, which in this
- * case is local party (i.e. us) and remote party.
- */
-typedef struct pjsip_dlg_party
-{
- pjsip_uri *target; /**< Target URL. */
- pjsip_fromto_hdr *info; /**< URL in From/To header. */
- pj_str_t tag; /**< Tag. */
- pjsip_contact_hdr *contact; /**< URL in Contact. */
- pj_sockaddr_in addr; /**< The current transport address. */
- int cseq; /**< Sequence number counter. */
-} pjsip_dlg_party;
-
-
-/**
- * This structure describes the dialog structure.
- */
-struct pjsip_dlg
-{
- PJ_DECL_LIST_MEMBER(struct pjsip_dlg)
-
- char obj_name[PJ_MAX_OBJ_NAME]; /**< Log identification. */
-
- pjsip_user_agent *ua; /**< User agent instance. */
- pj_pool_t *pool; /**< Dialog's pool. */
- pjsip_dlg_state_e state; /**< Dialog's call state. */
- pjsip_role_e role; /**< Dialog's role. */
- pj_mutex_t *mutex; /**< Dialog's mutex. */
-
- pjsip_dlg_party local; /**< Local party info. */
- pjsip_dlg_party remote; /**< Remote party info. */
-
- pjsip_cid_hdr *call_id; /**< Call-ID */
- pj_bool_t secure; /**< Use secure transport? */
-
- pjsip_route_hdr route_set; /**< Dialog's route set. */
- pjsip_transaction *invite_tsx; /**< Current INVITE transaction. */
- int pending_tsx_count; /**< Total pending tsx count. */
-
- int cred_count; /**< Number of credentials. */
- pjsip_cred_info *cred_info; /**< Array of credentials. */
-
- pjsip_auth_session auth_sess; /**< List of auth session. */
-
- pjsip_msg_body *body;
-
- void *user_data; /**< Application's data. */
-
- int (*handle_tsx_event)(struct pjsip_dlg *, /**< Internal state handler.*/
- pjsip_transaction *,
- pjsip_event *);
-};
-
-
-/**
- * Initialize dialog with local and remote info. This function is normally
- * called after application creates the dialog with #pjsip_ua_create_dialog
- * for UAC dialogs.
- *
- * This function will initialize local and remote info from the URL, generate
- * a globally unique Call-ID, initialize CSeq, and initialize other dialog's
- * internal attributes.
- *
- * @param dlg The dialog to initialize.
- * @param local_info URI/name address to be used as local info
- * (From and Contact headers).
- * @param remote_info URI/name address to be used as remote info (To header).
- * @param target URI for initial remote's target, or NULL to set the
- * initial target the same as remote_info.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
- const pj_str_t *local_info,
- const pj_str_t *remote_info,
- const pj_str_t *target);
-
-
-/**
- * Set authentication credentials to be used by this dialog.
- *
- * If authentication credentials are set for the dialog, the dialog will try to
- * perform authentication automatically using the credentials supplied, and
- * also cache the last Authorization or Proxy-Authorization headers for next
- * requests.
- *
- * If none of the credentials are suitable or accepted by remote, then
- * the dialog will just pass the authorization failure response back to
- * application.
- *
- * @param dlg The dialog.
- * @param count Number of credentials in the array.
- * @param cred Array of credentials.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
- int count,
- const pjsip_cred_info cred[]);
-
-/**
- * Override local contact details.
- *
- * Call this function to change the contact details to be advertised in Contact
- * header. Application normally need to call this function for incoming calls
- * before answering the call with 200/OK, because for an incoming dialogs, the
- * initial local contact info are generated from the To header, which is
- * normally not the appropriate one.
- *
- * @param dlg The dialog.
- * @param contact The contact to use.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
- const pj_str_t *contact );
-
-
-/**
- * Set initial route set to be used by the dialog. This initial route set
- * governs where and how the initial INVITE request will be routed. This
- * initial route set will be overwritten with the route set found in the
- * 2xx response of INVITE.
- *
- * Application only needs to call this function if it wants to have custom
- * route for individual dialogs. If only a single route for all dialogs is
- * needed, then application can set the global route by calling function
- * #pjsip_endpt_set_proxies().
- *
- * @param dlg The dialog.
- * @param route_set The route set list.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
- const pjsip_route_hdr *route_set );
-
-
-/**
- * Variation of #pjsip_dlg_set_route_set where the headers will be used
- * as it is (i.e. without cloned).
- *
- * @param dlg The dialog.
- * @param route_set The route set list.
- *
- * @return Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
- pjsip_route_hdr *route_set);
-
-/**
- * Create initial outgoing INVITE message.
- *
- * This function is just a simple wrapper to #pjsip_dlg_create_request(),
- * so it follows the same rule there. In addition, this function also adds
- * \b Allow header to the outgoing request.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- *
- * @return The dialog transmit data, or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg );
-
-
-/**
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response. Application can only call this function when there's
- * a pending invitation to be answered.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @param code The response code, which can be:
- * - 100-199 Provisional response (application can issue multiple
- * provisional responses).
- * - 200-299 To answer the invitation (normally status code 200
- * is sent).
- * - 300-699 To reject the invitation.
- * @return Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code );
-
-
-/**
- * High level function to create message to disconnect dialog. Depending
- * on dialog's state, this function will either create CANCEL, final response,
- * or BYE message. A status code must be supplied, which will be set if dialog
- * will be transmitting a final response to INVITE.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @param status_code The status code for disconnection.
- * @return Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, int status_code);
-
-/**
- * Create CANCEL message to cancel pending outgoing dialog invitation.
- * Normally application should call #pjsip_dlg_disconnect() instead, because
- * that function will create the correct message regardless of the state of
- * the dialog.
- *
- * Application can call this function at anytime after it issues outgoing
- * invitation and before receiving final response. However, there's no
- * guarantee that the invitation will be successfully cancelled, since the
- * CANCEL request and the final response can pass over in the wire. So the
- * application must prepare to have the dialog connected even after the
- * dialog is cancelled.
- *
- * The final state of the dialog will be reported in the dialog callback.
- * If the CANCEL request succeeded, then the dialog will be disconnected with
- * status code \a PJSIP_SC_REQUEST_TERMINATED.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state.
- *
- * Upon return of this function, the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @return The dialog transmit data containing the CANCEL message,
- * or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg );
-
-
-/**
- * Create BYE message. Application shouldn't normally need to use this function,
- * but rather it's preferable to use #pjsip_dlg_disconnect() instead because
- * that function will work to disconnect the session no matter what the state
- * is.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg The dialog.
- * @return The BYE message or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg );
-
-/**
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request
- * by calling #pjsip_dlg_send_msg().
- *
- * This function will initialize the request message with dialog's properties
- * as follows:
- * - the request line is initialized with the method and the target is
- * initialized from current remote target.
- * - \b From, \b To, \b Contact, and \b Call-Id headers will be added.
- * - An initial \b CSeq header will be provided (although the value will be
- * verified again when the message is actually sent with #pjsip_dlg_send_msg().
- * - \b Route headers will be added from dialog's route set.
- * - Authentication headers (\b Authorization or \b Proxy-Authorization) will
- * be added from dialog's authorization cache.
- *
- * Note that upon return the reference counter of the transmit data
- * will be set to one. When the message is sent, #pjsip_dlg_send_msg() will
- * decrement the reference counter, and when the reference counter reach zero,
- * the message will be deleted.
- *
- * @param dlg The dialog.
- * @param method The request method.
- * @param cseq Specify CSeq, or -1 to let the dialog specify CSeq.
- *
- * @return Transmit data for the new request.
- *
- * @see pjsip_dlg_send_msg()
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq);
-
-
-/**
- * This function can be called by application to send outgoing message (request
- * or response) to remote party. Note that after calling this function, the
- * transmit data will be deleted regardless of the return status. To prevent
- * deletion, application must increase the reference count, but then it will
- * be responsible to delete this transmit data itself (by decreasing the
- * reference count).
- *
- * @param dlg The dialog.
- * @param tdata The transmit data, which contains the request message.
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg,
- pjsip_tx_data *tdata );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif /* __PJSIP_DIALOG_H__ */
-
diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip.h
index 5947d4b1..b7f2dd95 100644
--- a/pjsip/include/pjsip_core.h
+++ b/pjsip/include/pjsip.h
@@ -16,25 +16,41 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_CORE_H__
-#define __PJSIP_CORE_H__
+#ifndef __PJSIP_H__
+#define __PJSIP_H__
+/* Base types. */
#include <pjsip/sip_types.h>
-#include <pjsip/sip_auth.h>
-#include <pjsip/sip_endpoint.h>
#include <pjsip/sip_errno.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_module.h>
+
+/* Messaging and parsing. */
+#include <pjsip/sip_uri.h>
+#include <pjsip/sip_tel_uri.h>
#include <pjsip/sip_msg.h>
#include <pjsip/sip_parser.h>
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_tel_uri.h>
-#include <pjsip/sip_transaction.h>
+
+/* Core */
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_util.h>
+
+/* Transport layer */
#include <pjsip/sip_transport.h>
#include <pjsip/sip_transport_udp.h>
#include <pjsip/sip_transport_loop.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
+#include <pjsip/sip_resolve.h>
+
+/* Authentication. */
+#include <pjsip/sip_auth.h>
+
+/* Transaction layer. */
+#include <pjsip/sip_transaction.h>
+
+/* UA Layer. */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_dialog.h>
+
-#endif /* __PJSIP_CORE_H__ */
+#endif /* __PJSIP_H__ */
diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h
index e5f80655..7a8eb610 100644
--- a/pjsip/include/pjsip/sip_auth.h
+++ b/pjsip/include/pjsip/sip_auth.h
@@ -187,6 +187,18 @@ PJ_DECL(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
unsigned options);
+/**
+ * Clone client initialization session.
+ *
+ * @param pool Pool to use.
+ * @param sess Structure to put the duplicated session.
+ * @param rhs The client session to be cloned.
+ *
+ * @return PJ_SUCCESS on success;
+ */
+PJ_DECL(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+ pjsip_auth_clt_sess *sess,
+ const pjsip_auth_clt_sess *rhs);
/**
* Set the credentials to be used during the session. This will duplicate
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 158d4a75..ec4a4aad 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -53,6 +53,10 @@
#define PJSIP_POOL_TSX_INC 256
#define PJSIP_MAX_TSX_KEY_LEN (PJSIP_MAX_URL_SIZE*2)
+/* User agent. */
+#define PJSIP_POOL_LEN_USER_AGENT 1024
+#define PJSIP_POOL_INC_USER_AGENT 1024
+
/* Message/URL related constants. */
#define PJSIP_MAX_CALL_ID_LEN PJ_GUID_STRING_LENGTH
#define PJSIP_MAX_TAG_LEN PJ_GUID_STRING_LENGTH
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
new file mode 100644
index 00000000..9e827c78
--- /dev/null
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -0,0 +1,324 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJSIP_SIP_DIALOG_H__
+#define __PJSIP_SIP_DIALOG_H__
+
+
+/**
+ * @file dialog.h
+ * @brief SIP Dialog abstraction
+ */
+
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_auth.h>
+#include <pjsip/sip_errno.h>
+#include <pj/sock.h>
+#include <pj/assert.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * This structure is used to describe dialog's participants, which in this
+ * case is local party (i.e. us) and remote party.
+ */
+typedef struct pjsip_dlg_party
+{
+ pjsip_fromto_hdr *info; /**< From/To header, inc tag. */
+ pj_uint32_t tag_hval; /**< Hashed value of the tag. */
+ pjsip_contact_hdr *contact; /**< Contact header. */
+ pj_int32_t first_cseq;/**< First CSeq seen. */
+ pj_int32_t cseq; /**< Next sequence number. */
+} pjsip_dlg_party;
+
+
+/**
+ * This structure describes the dialog structure.
+ */
+struct pjsip_dialog
+{
+ /** The dialog set list. */
+ PJ_DECL_LIST_MEMBER(pjsip_dialog);
+
+ /* Dialog's system properties. */
+ char obj_name[PJ_MAX_OBJ_NAME]; /**< Standard id. */
+ pj_pool_t *pool; /**< Dialog's pool. */
+ pj_mutex_t *mutex; /**< Dialog's mutex. */
+ pjsip_user_agent *ua; /**< User agent instance. */
+
+ /* The dialog set. */
+ void *dlg_set;
+
+ /* Dialog's session properties. */
+ pjsip_uri *target; /**< Current target. */
+ pjsip_dlg_party local; /**< Local party info. */
+ pjsip_dlg_party remote; /**< Remote party info. */
+ pjsip_role_e role; /**< Initial role. */
+ pj_bool_t secure; /**< Use secure transport? */
+ pjsip_cid_hdr *call_id; /**< Call-ID header. */
+ pjsip_route_hdr route_set; /**< Route set. */
+ pjsip_auth_clt_sess auth_sess; /**< Client authentication session. */
+
+ /** Session counter. */
+ int sess_count;
+
+ /** Transaction counter. */
+ int tsx_count;
+
+ /* Dialog usages. */
+ unsigned usage_cnt; /**< Number of registered usages. */
+ pjsip_module *usage[PJSIP_MAX_MODULE]; /**< Array of usages, priority sorted */
+
+ /** Module specific data. */
+ void *mod_data[PJSIP_MAX_MODULE];
+};
+
+
+/**
+ * This utility function returns PJ_TRUE if the specified method is a
+ * dialog creating request. This method property is used to determine
+ * whether Contact header should be included in outgoing request.
+ */
+PJ_DECL(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m);
+
+/**
+ * Create a new dialog and return the instance in p_dlg parameter.
+ * After creating the dialog, application can add modules as dialog usages
+ * by calling #pjsip_dlg_add_usage().
+ *
+ * If the request has To tag parameter, dialog's local tag will be initialized
+ * from this value. Otherwise a globally unique id generator will be invoked to
+ * create dialog's local tag.
+ *
+ * This function also initializes the dialog's route set based on the
+ * Record-Route headers in the request, if present.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+ const pj_str_t *local_uri,
+ const pj_str_t *local_contact_uri,
+ const pj_str_t *remote_uri,
+ const pj_str_t *target,
+ pjsip_dialog **p_dlg);
+
+
+/**
+ * Initialize UAS dialog from the information found in the incoming request
+ * that creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the
+ * local Contact to contact. If contact is not specified, the local contact
+ * is initialized from the URI in the To header in the request.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg);
+
+
+/**
+ * Create a new (forked) dialog on receipt on forked response in rdata.
+ * The new dialog will be created from original_dlg, except that it will have
+ * new remote tag as copied from the To header in the response. Upon return,
+ * the new_dlg will have been registered to the user agent. Applications just
+ * need to add modules as dialog's usages.
+ *
+ * Note that initially, the session count in the dialog will be initialized
+ * to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_fork(const pjsip_dialog *original_dlg,
+ const pjsip_rx_data *rdata,
+ pjsip_dialog **new_dlg );
+
+/**
+ * Set dialog's initial route set to route_set list. This can only be called
+ * for UAC dialog, before any request is sent. After dialog has been
+ * established, the route set can not be changed.
+ *
+ * For UAS dialog,the route set will be initialized in pjsip_dlg_create_uas()
+ * from the Record-Route headers in the incoming request.
+ *
+ * The route_set argument is standard list of Route headers (i.e. with
+ * sentinel).
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+ const pjsip_route_hdr *route_set );
+
+/**
+ * Increment the number of sessions in the dialog. Note that initially
+ * (after created) the dialog has the session counter set to zero.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg );
+
+
+/**
+ * Decrement the number of sessions in the dialog. Once the session counter
+ * reach zero and there is no pending transaction, the dialog will be
+ * destroyed. Note that this function may destroy the dialog immediately
+ * if there is no pending transaction when this function is called.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg );
+
+/**
+ * Add a module as dialog usage, and optionally set the module specific data.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+ pjsip_module *module,
+ void *mod_data );
+
+/**
+ * Attach module specific data to the dialog. Application can also set
+ * the value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg,
+ int mod_id,
+ void *data )
+{
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+ PJ_EINVAL);
+ dlg->mod_data[mod_id] = data;
+ return PJ_SUCCESS;
+}
+
+/**
+ * Get module specific data previously attached to the dialog. Application
+ * can also get value directly by accessing dlg->mod_data[module_id].
+ */
+PJ_INLINE(void*) pjsip_dlg_get_mod_data(pjsip_dialog *dlg,
+ int mod_id)
+{
+ PJ_ASSERT_RETURN(dlg, NULL);
+ PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
+ NULL);
+ return dlg->mod_data[mod_id];
+}
+
+
+
+/**
+ * Get the dialog instance in the incoming rdata. If an incoming message
+ * matches an existing dialog, the user agent must have put the matching
+ * dialog instance in the rdata, or otherwise this function will return
+ * NULL if the message didn't match any existing dialog.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata );
+
+/**
+ * Get the associated dialog in a transaction.
+ */
+PJ_DECL(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx );
+
+
+/**
+ * Create a basic/generic request with the specified method and optionally
+ * specify the cseq. Use value -1 for cseq to have the dialog automatically
+ * put next cseq number for the request. Otherwise for some requests,
+ * e.q. CANCEL and ACK, application must put the CSeq in the original
+ * INVITE request as the parameter.
+ *
+ * This function will also put Contact header where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **tdata);
+
+
+/**
+ * Send request message to remote peer. If the request is not an ACK request,
+ * the dialog will send the request statefully, by creating an UAC transaction
+ * and send the request with the transaction.
+ *
+ * Also when the request is not ACK or CANCEL, the dialog will increment its
+ * local cseq number and update the cseq in the request according to dialog's
+ * cseq.
+ *
+ * If p_tsx is not null, this argument will be set with the transaction
+ * instance that was used to send the request.
+ *
+ * This function will decrement the transmit data's reference counter
+ * regardless the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_request ( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ pjsip_transaction **p_tsx );
+
+
+/**
+ * Create a response message for the incoming request in rdata with status
+ * code st_code and optional status text st_text. This function is different
+ * than endpoint's API #pjsip_endpt_create_response() in that the dialog
+ * function adds Contact header and Record-Routes headers in the response
+ * where appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ pjsip_tx_data **tdata);
+
+
+/**
+ * Modify previously sent response with other status code. Contact header
+ * will be added when appropriate.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ int st_code,
+ const pj_str_t *st_text);
+
+
+/**
+ * Send response message statefully. The transaction instance MUST be the
+ * transaction that was reported on on_rx_request() callback.
+ *
+ * This function decrements the transmit data's reference counter regardless
+ * the status of the operation.
+ */
+PJ_DECL(pj_status_t) pjsip_dlg_send_response( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_tx_data *tdata);
+
+
+
+/* Receives transaction event (called by user_agent module) */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_event *e );
+
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata );
+
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJSIP_SIP_DIALOG_H__ */
+
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index 527cd886..ef9d44c9 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -228,6 +228,19 @@ PJ_DECL(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt,
pjsip_transaction **p_tsx);
/**
+ * Find transaction in endpoint's transaction table by the transaction's key.
+ * This function normally is only used by modules. The key for a transaction
+ * can be created by calling #pjsip_tsx_create_key.
+ *
+ * @param endpt The endpoint instance.
+ * @param key Transaction key, as created with #pjsip_tsx_create_key.
+ *
+ * @return The transaction, or NULL if it's not found.
+ */
+PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
+ const pj_str_t *key );
+
+/**
* Register the transaction to the endpoint's transaction table.
* Before the transaction is registered, it must have been initialized as
* either UAS or UAC by calling #pjsip_tsx_init_uac or #pjsip_tsx_init_uas.
@@ -316,40 +329,78 @@ pjsip_endpt_acquire_transport( pjsip_endpoint *endpt,
int addr_len,
pjsip_transport **p_transport);
-/**
- * Get additional headers to be put in outgoing request message.
- * This function is normally called by transaction layer when sending outgoing
- * requests.
- *
- * @param endpt The endpoint.
+
+/*****************************************************************************
*
- * @return List of additional headers to be put in outgoing requests.
+ * Capabilities Management
+ *
+ * Modules may implement new capabilities to the stack. These capabilities
+ * are indicated by the appropriate SIP header fields, such as Accept,
+ * Accept-Encoding, Accept-Language, Allow, Supported, etc.
+ *
+ * When a module provides new capabilities to the stack, it registers these
+ * capabilities to the endpoint by supplying new tags (strings) to the
+ * appropriate header fields. Application (or other modules) can then query
+ * these header fields to get the list of supported capabilities, and may
+ * include these headers in the outgoing message.
+ *****************************************************************************
*/
-PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt);
/**
- * Get "Allow" header from endpoint. The endpoint builds the "Allow" header
- * from the list of methods supported by modules.
+ * Get the value of the specified capability header field.
*
* @param endpt The endpoint.
+ * @param htype The header type to be retrieved, which value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header name
+ * must be supplied in this argument. Otherwise the value
+ * must be set to NULL.
*
- * @return "Allow" header, or NULL if endpoint doesn't have "Allow" header.
+ * @return The appropriate header, or NULL if the header is not
+ * available.
*/
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt );
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+ int htype,
+ const pj_str_t *hname);
/**
- * Find transaction in endpoint's transaction table by the transaction's key.
- * This function normally is only used by modules. The key for a transaction
- * can be created by calling #pjsip_tsx_create_key.
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
*
- * @param endpt The endpoint instance.
- * @param key Transaction key, as created with #pjsip_tsx_create_key.
+ * @param endpt The endpoint.
+ * @param mod The module which registers the capability.
+ * @param htype The header type to be set, which value may be:
+ * - PJSIP_H_ACCEPT
+ * - PJSIP_H_ALLOW
+ * - PJSIP_H_SUPPORTED
+ * @param hname If htype specifies PJSIP_H_OTHER, then the header name
+ * must be supplied in this argument. Otherwise the value
+ * must be set to NULL.
+ * @param count The number of tags in the array.
+ * @param tags Array of tags describing the capabilities or extensions
+ * to be added to the appropriate header.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+ pjsip_module *mod,
+ int htype,
+ const pj_str_t *hname,
+ unsigned count,
+ const pj_str_t tags[]);
+
+/**
+ * Get list of additional headers to be put in outgoing request message.
*
- * @return The transaction, or NULL if it's not found.
+ * @param e The endpoint.
+ *
+ * @return List of headers.
*/
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
- const pj_str_t *key );
+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *e);
+
/**
* Set list of SIP proxies to be visited for all outbound request messages.
diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h
index 9c04c755..f7dc18cc 100644
--- a/pjsip/include/pjsip/sip_errno.h
+++ b/pjsip/include/pjsip/sip_errno.h
@@ -140,6 +140,11 @@ PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
/**
* @hideinitializer
+ * General Invalid URI error.
+ */
+#define PJSIP_EINVALIDURI (PJSIP_ERRNO_START_PJSIP + 39) /* 171039 */
+/**
+ * @hideinitializer
* Unsupported URL scheme.
*/
#define PJSIP_EINVALIDSCHEME (PJSIP_ERRNO_START_PJSIP + 40) /* 171040 */
@@ -347,6 +352,17 @@ PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer,
#define PJSIP_EAUTHINVALIDDIGEST (PJSIP_ERRNO_START_PJSIP+110) /* 171110 */
+/************************************************************
+ * UA AND DIALOG ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Missing From/To tag.
+ */
+#define PJSIP_EMISSINGTAG (PJSIP_ERRNO_START_PJSIP+120) /* 171120 */
+
+
+
PJ_END_DECL
#endif /* __PJSIP_SIP_ERRNO_H__ */
diff --git a/pjsip/include/pjsip/sip_module.h b/pjsip/include/pjsip/sip_module.h
index 161e43d2..57d1652d 100644
--- a/pjsip/include/pjsip/sip_module.h
+++ b/pjsip/include/pjsip/sip_module.h
@@ -24,6 +24,7 @@
* @brief Module helpers
*/
#include <pjsip/sip_types.h>
+#include <pj/list.h>
PJ_BEGIN_DECL
@@ -68,16 +69,6 @@ struct pjsip_module
void *user_data;
/**
- * Number of methods supported by this module.
- */
- int method_cnt;
-
- /**
- * Array of methods supported by this module.
- */
- const pjsip_method *methods[8];
-
- /**
* Pointer to function to be called to initialize the module.
*
* @param endpt The endpoint instance.
diff --git a/pjsip/include/pjsip/sip_msg.h b/pjsip/include/pjsip/sip_msg.h
index 3be3c2f8..cebaf3f0 100644
--- a/pjsip/include/pjsip/sip_msg.h
+++ b/pjsip/include/pjsip/sip_msg.h
@@ -173,48 +173,48 @@ typedef enum pjsip_hdr_e
* DO NOT CHANGE THE VALUE/ORDER OF THE HEADER IDs!!!.
*/
PJSIP_H_ACCEPT,
- PJSIP_H_ACCEPT_ENCODING_UNIMP,
- PJSIP_H_ACCEPT_LANGUAGE_UNIMP,
- PJSIP_H_ALERT_INFO_UNIMP,
+ PJSIP_H_ACCEPT_ENCODING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ACCEPT_LANGUAGE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ALERT_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_ALLOW,
- PJSIP_H_AUTHENTICATION_INFO_UNIMP,
+ PJSIP_H_AUTHENTICATION_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_AUTHORIZATION,
PJSIP_H_CALL_ID,
- PJSIP_H_CALL_INFO_UNIMP,
+ PJSIP_H_CALL_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_CONTACT,
- PJSIP_H_CONTENT_DISPOSITION_UNIMP,
- PJSIP_H_CONTENT_ENCODING_UNIMP,
- PJSIP_H_CONTENT_LANGUAGE_UNIMP,
+ PJSIP_H_CONTENT_DISPOSITION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_CONTENT_ENCODING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_CONTENT_LANGUAGE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_CONTENT_LENGTH,
PJSIP_H_CONTENT_TYPE,
PJSIP_H_CSEQ,
- PJSIP_H_DATE_UNIMP,
- PJSIP_H_ERROR_INFO_UNIMP,
+ PJSIP_H_DATE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_ERROR_INFO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_EXPIRES,
PJSIP_H_FROM,
- PJSIP_H_IN_REPLY_TO_UNIMP,
+ PJSIP_H_IN_REPLY_TO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_MAX_FORWARDS,
- PJSIP_H_MIME_VERSION_UNIMP,
+ PJSIP_H_MIME_VERSION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_MIN_EXPIRES,
- PJSIP_H_ORGANIZATION_UNIMP,
- PJSIP_H_PRIORITY_UNIMP,
+ PJSIP_H_ORGANIZATION_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_PRIORITY_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_PROXY_AUTHENTICATE,
PJSIP_H_PROXY_AUTHORIZATION,
- PJSIP_H_PROXY_REQUIRE_UNIMP,
+ PJSIP_H_PROXY_REQUIRE_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_RECORD_ROUTE,
- PJSIP_H_REPLY_TO_UNIMP,
+ PJSIP_H_REPLY_TO_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_REQUIRE,
PJSIP_H_RETRY_AFTER,
PJSIP_H_ROUTE,
- PJSIP_H_SERVER_UNIMP,
- PJSIP_H_SUBJECT_UNIMP,
+ PJSIP_H_SERVER_UNIMP, /* N/A, use pjsip_generic_string_hdr */
+ PJSIP_H_SUBJECT_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_SUPPORTED,
- PJSIP_H_TIMESTAMP_UNIMP,
+ PJSIP_H_TIMESTAMP_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_TO,
PJSIP_H_UNSUPPORTED,
- PJSIP_H_USER_AGENT_UNIMP,
+ PJSIP_H_USER_AGENT_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_VIA,
- PJSIP_H_WARNING_UNIMP,
+ PJSIP_H_WARNING_UNIMP, /* N/A, use pjsip_generic_string_hdr */
PJSIP_H_WWW_AUTHENTICATE,
PJSIP_H_OTHER,
@@ -748,6 +748,49 @@ PJ_INLINE(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr )
PJ_DECL(pj_ssize_t) pjsip_msg_print(const pjsip_msg *msg,
char *buf, pj_size_t size);
+
+/*
+ * Some usefull macros to find common headers.
+ */
+
+
+/**
+ * Find Call-ID header.
+ *
+ * @param msg The message.
+ * @return Call-ID header instance.
+ */
+#define PJSIP_MSG_CID_HDR(msg) \
+ ((pjsip_cid_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CALL_ID, NULL))
+
+/**
+ * Find CSeq header.
+ *
+ * @param msg The message.
+ * @return CSeq header instance.
+ */
+#define PJSIP_MSG_CSEQ_HDR(msg) \
+ ((pjsip_cseq_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL))
+
+/**
+ * Find From header.
+ *
+ * @param msg The message.
+ * @return From header instance.
+ */
+#define PJSIP_MSG_FROM_HDR(msg) \
+ ((pjsip_from_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL))
+
+/**
+ * Find To header.
+ *
+ * @param msg The message.
+ * @return To header instance.
+ */
+#define PJSIP_MSG_TO_HDR(msg) \
+ ((pjsip_to_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL))
+
+
/**
* @}
*/
@@ -766,8 +809,10 @@ PJ_DECL(pj_ssize_t) pjsip_msg_print(const pjsip_msg *msg,
*/
typedef struct pjsip_generic_string_hdr
{
- PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr); /**< Standard header field. */
- pj_str_t hvalue; /**< hvalue */
+ /** Standard header field. */
+ PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr);
+ /** hvalue */
+ pj_str_t hvalue;
} pjsip_generic_string_hdr;
@@ -778,25 +823,38 @@ typedef struct pjsip_generic_string_hdr
* @param pool The pool.
* @param hname The header name to be assigned to the header, or NULL to
* assign the header name with some string.
+ * @param hvalue Optional string to be assigned as the value.
*
* @return The header, or THROW exception.
*/
-PJ_DECL(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
- const pj_str_t *hname );
+PJ_DECL(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hname,
+ const pj_str_t *hvalue);
/**
- * Create a generic header along with the text content.
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
*
- * @param pool The pool.
- * @param hname The header name.
- * @param hvalue The header text content.
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ * @param hvalue Optional string to be assigned as the value.
*
- * @return The header instance.
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
*/
PJ_DECL(pjsip_generic_string_hdr*)
-pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
- const pj_str_t *hname,
- const pj_str_t *hvalue);
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname,
+ const pj_str_t *hvalue);
+
/**
* @}
@@ -827,25 +885,36 @@ typedef struct pjsip_generic_int_hdr
* @param pool The pool.
* @param hname The header name to be assigned to the header, or NULL to
* assign the header name with some string.
+ * @param hvalue The value to be assigned to the header.
*
* @return The header, or THROW exception.
*/
-PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
- const pj_str_t *hname );
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hname,
+ int hvalue );
+
/**
- * Create a generic header along with the value.
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
*
- * @param pool The pool.
- * @param hname The header name.
- * @param value The header value content.
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ * @param value Value to be assigned to the header.
*
- * @return The header instance.
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
*/
-PJ_DECL(pjsip_generic_int_hdr*)
-pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
- const pj_str_t *hname,
- int value);
+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname,
+ int value );
/**
* @}
@@ -873,11 +942,33 @@ typedef struct pjsip_generic_array_hdr
* Create generic array header.
*
* @param pool Pool to allocate memory from.
+ * @param hname Header name.
*
* @return New generic array header.
*/
-PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_create(pj_pool_t *pool,
- const pj_str_t *hnames);
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create(pj_pool_t *pool,
+ const pj_str_t *hname);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param hname The header name to be assigned to the header, or NULL to
+ * assign the header name with some string later.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init(pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hname);
+
/**
* @}
@@ -905,6 +996,22 @@ typedef pjsip_generic_array_hdr pjsip_accept_hdr;
*/
PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -929,6 +1036,24 @@ typedef pjsip_generic_array_hdr pjsip_allow_hdr;
PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* @}
*/
@@ -961,6 +1086,24 @@ PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+
+/**
* @}
*/
@@ -989,6 +1132,24 @@ typedef struct pjsip_clen_hdr
PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+
+/**
* @}
*/
@@ -1018,6 +1179,23 @@ typedef struct pjsip_cseq_hdr
PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1054,6 +1232,23 @@ typedef struct pjsip_contact_hdr
PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1083,6 +1278,23 @@ typedef struct pjsip_ctype_hdr
PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
@@ -1099,10 +1311,33 @@ typedef pjsip_generic_int_hdr pjsip_expires_hdr;
/**
* Create a new Expires header.
*
- * @param pool The pool.
- * @return A new Expires header.
+ * @param pool The pool.
+ * @param value The expiration value.
+ *
+ * @return A new Expires header.
*/
-PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool );
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+ int value);
+
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The expiration value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
+
/**
* @}
@@ -1141,6 +1376,23 @@ typedef pjsip_fromto_hdr pjsip_to_hdr;
PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* Create a To header.
*
* @param pool The pool.
@@ -1149,12 +1401,29 @@ PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );
PJ_DECL(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* Convert the header to a From header.
*
* @param pool The pool.
* @return "From" header.
*/
-PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr );
/**
* Convert the header to a To header.
@@ -1162,7 +1431,7 @@ PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
* @param pool The pool.
* @return "To" header.
*/
-PJ_DECL(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
+PJ_DECL(pjsip_to_hdr*) pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr );
/**
* @}
@@ -1176,19 +1445,39 @@ PJ_DECL(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
* @ingroup PJSIP_MSG
* @{
*/
-typedef pjsip_generic_int_hdr pjsip_max_forwards_hdr;
+typedef pjsip_generic_int_hdr pjsip_max_fwd_hdr;
/**
* Create new Max-Forwards header instance.
*
* @param pool The pool.
+ * @param value The Max-Forwards value.
*
* @return New Max-Forwards header instance.
*/
-PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_max_fwd_hdr*)
+pjsip_max_fwd_hdr_create(pj_pool_t *pool, int value);
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Max-Forwards value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_max_fwd_hdr*)
+pjsip_max_fwd_hdr_init( pj_pool_t *pool, void *mem, int value );
+
+/**
* @}
*/
@@ -1203,16 +1492,37 @@ PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
typedef pjsip_generic_int_hdr pjsip_min_expires_hdr;
/**
- * Create new Max-Forwards header instance.
+ * Create new Min-Expires header instance.
*
* @param pool The pool.
+ * @param value The Min-Expires value.
*
- * @return New Max-Forwards header instance.
+ * @return New Min-Expires header instance.
*/
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+ int value);
/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Min-Expires value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
+
+/**
* @}
*/
@@ -1249,6 +1559,23 @@ typedef pjsip_routing_hdr pjsip_route_hdr;
*/
PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool );
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* Create new Route header from the pool.
*
@@ -1257,6 +1584,23 @@ PJ_DECL(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool );
*/
PJ_DECL(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool );
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+ void *mem );
+
/**
* Convert generic routing header to Record-Route header.
*
@@ -1295,6 +1639,22 @@ typedef pjsip_generic_array_hdr pjsip_require_hdr;
*/
PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure. This function
+ * should only be called when application uses its own memory allocation to
+ * allocate memory block for the specified header (e.g. in C++, when the
+ * header is allocated with "new" operator).
+ * For normal applications, they should use pjsip_xxx_hdr_create() instead,
+ * which allocates memory and initialize it in one go.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1314,10 +1674,26 @@ typedef pjsip_generic_int_hdr pjsip_retry_after_hdr;
* Create new Retry-After header instance.
*
* @param pool The pool.
+ * @param value The Retry-After value.
*
* @return New Retry-After header instance.
*/
-PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool);
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+ int value);
+
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ * @param value The Retry-After value.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value );
/**
@@ -1342,6 +1718,17 @@ typedef pjsip_generic_array_hdr pjsip_supported_hdr;
*/
PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1365,6 +1752,17 @@ typedef pjsip_generic_array_hdr pjsip_unsupported_hdr;
*/
PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool);
+/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+ void *mem );
/**
* @}
@@ -1408,6 +1806,18 @@ typedef struct pjsip_via_hdr
PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool );
/**
+ * Initialize a preallocated memory with the header structure.
+ *
+ * @param pool Pool for additional memory allocation if required.
+ * @param mem Pre-allocated memory to be initialized as the header.
+ *
+ * @return The header instance, which points to the same memory
+ * location as the mem argument.
+ */
+PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+ void *mem );
+
+/**
* @}
*/
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 065b71c2..712fa8ad 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -75,6 +75,7 @@ struct pjsip_transaction
pjsip_method method; /**< The method. */
int cseq; /**< The CSeq */
pj_str_t transaction_key;/**< Hash table key. */
+ pj_uint32_t hashed_key; /**< Key's hashed value. */
pj_str_t branch; /**< The branch Id. */
/*
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index f8968f90..5dd23c1f 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -67,6 +67,12 @@ enum pjsip_transport_flags_e
((tp)->flag & PJSIP_TRANSPORT_RELIABLE)
/**
+ * Check if transport tp is secure.
+ */
+#define PJSIP_TRANSPORT_IS_SECURE(tp) \
+ ((tp)->flag & PJSIP_TRANSPORT_SECURE)
+
+/**
* Get the transport type from the transport name.
*
* @param name Transport name, such as "TCP", or "UDP".
@@ -233,7 +239,7 @@ struct pjsip_rx_data
pjsip_cseq_hdr *cseq;
/** Max forwards header. */
- pjsip_max_forwards_hdr *max_fwd;
+ pjsip_max_fwd_hdr *max_fwd;
/** The first route header. */
pjsip_route_hdr *route;
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 72fe3af5..fc79f95a 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -102,6 +102,11 @@ typedef struct pjsip_hdr pjsip_hdr;
typedef struct pjsip_uri pjsip_uri;
/**
+ * Forward declaration for SIP method (sip_msg.h)
+ */
+typedef struct pjsip_method pjsip_method;
+
+/**
* Opaque data type for the resolver engine (sip_resolve.h).
*/
typedef struct pjsip_resolver_t pjsip_resolver_t;
@@ -117,6 +122,18 @@ typedef struct pjsip_cred_info pjsip_cred_info;
*/
typedef struct pjsip_module pjsip_module;
+
+/**
+ * Forward declaration for user agent type (sip_ua_layer.h).
+ */
+typedef pjsip_module pjsip_user_agent;
+
+/**
+ * Forward declaration for dialog (sip_dialog.h).
+ */
+typedef struct pjsip_dialog pjsip_dialog;
+
+
/**
* Transaction role.
*/
diff --git a/pjsip/include/pjsip-ua/sip_ua.h b/pjsip/include/pjsip/sip_ua_layer.h
index a1d7c423..e12a55a8 100644
--- a/pjsip/include/pjsip-ua/sip_ua.h
+++ b/pjsip/include/pjsip/sip_ua_layer.h
@@ -16,13 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_SIP_UA_H__
-#define __PJSIP_SIP_UA_H__
+#ifndef __PJSIP_SIP_UA_LAYER_H__
+#define __PJSIP_SIP_UA_LAYER_H__
/**
- * @file sip_ua.h
- * @brief SIP User Agent Module
+ * @file sip_ua_layer.h
+ * @brief SIP User Agent Layer Module
*/
+#include <pjsip/sip_types.h>
PJ_BEGIN_DECL
@@ -32,26 +33,30 @@ PJ_BEGIN_DECL
*/
/**
- * @defgroup PJSUA_UA SIP User Agent
+ * @defgroup PJSUA_UA SIP User Agent Module
* @ingroup PJSUA
* @{
* \brief
* User Agent manages the interactions between application and SIP dialogs.
*/
-/** User agent type. */
-typedef pjsip_module pjsip_user_agent;
-
+/** User agent initialization parameter. */
+typedef struct pjsip_ua_init_param
+{
+ pjsip_dialog* (*on_dlg_forked)(pjsip_dialog *first_set, pjsip_rx_data *res);
+} pjsip_ua_init_param;
/**
* Initialize user agent layer and register it to the specified endpoint.
*
* @param endpt The endpoint where the user agent will be
* registered.
+ * @param prm UA initialization parameter.
*
* @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt);
+PJ_DECL(pj_status_t) pjsip_ua_init(pjsip_endpoint *endpt,
+ const pjsip_ua_init_param *prm);
/**
* Get the instance of the user agent.
@@ -67,6 +72,26 @@ PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void);
*/
PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
+/**
+ * Get the endpoint instance of a user agent module.
+ *
+ * @param ua The user agent instance.
+ *
+ * @return The endpoint instance where the user agent is
+ * registered.
+ */
+PJ_DECL(pjsip_endpoint*) pjsip_ua_get_endpt(pjsip_user_agent *ua);
+
+
+/*
+ * Internal.
+ */
+
+PJ_DECL(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg );
+PJ_DECL(pj_status_t) pjsip_ua_unregister_dlg(pjsip_user_agent *ua,
+ pjsip_dialog *dlg );
+
/**
* @}
@@ -75,5 +100,5 @@ PJ_DECL(pj_status_t) pjsip_ua_destroy(void);
PJ_END_DECL
-#endif /* __PJSIP_UA_H__ */
+#endif /* __PJSIP_SIP_UA_LAYER_H__ */
diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 3ee19354..6973c524 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -161,9 +161,9 @@ typedef struct pjsip_uri_vptr
* @param size the size of the buffer.
* @return the length printed.
*/
- int (*p_print)(pjsip_uri_context_e context,
- const void *uri,
- char *buf, pj_size_t size);
+ pj_ssize_t (*p_print)(pjsip_uri_context_e context,
+ const void *uri,
+ char *buf, pj_size_t size);
/**
* Compare two URIs according to the context.
@@ -332,20 +332,20 @@ PJ_INLINE(void*) pjsip_uri_clone( pj_pool_t *pool, const void *uri )
* @param secure Tlag to indicate whether secure transport should be used.
* @return SIP URL.
*/
-PJ_DECL(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure );
+PJ_DECL(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure );
/**
* Create new SIPS URL and initialize all fields with zero or NULL.
* @param pool The pool.
* @return SIPS URL.
*/
-PJ_DECL(pjsip_sip_uri*) pjsips_url_create( pj_pool_t *pool );
+PJ_DECL(pjsip_sip_uri*) pjsip_sips_uri_create( pj_pool_t *pool );
/**
* Initialize SIP URL (all fields are set to NULL or zero).
* @param url The URL.
*/
-PJ_DECL(void) pjsip_url_init(pjsip_sip_uri *url, int secure);
+PJ_DECL(void) pjsip_sip_uri_init(pjsip_sip_uri *url, int secure);
/**
* Perform full assignment to the SIP URL.
@@ -353,8 +353,8 @@ PJ_DECL(void) pjsip_url_init(pjsip_sip_uri *url, int secure);
* @param url Destination URL.
* @param rhs The source URL.
*/
-PJ_DECL(void) pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url,
- const pjsip_sip_uri *rhs);
+PJ_DECL(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
+ const pjsip_sip_uri *rhs);
/**
* Create new instance of name address and initialize all fields with zero or
diff --git a/pjsip/src/pjsip-ua/sip_dialog.c b/pjsip/src/pjsip-ua/sip_dialog.c
deleted file mode 100644
index 722c06d8..00000000
--- a/pjsip/src/pjsip-ua/sip_dialog.c
+++ /dev/null
@@ -1,1802 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_parser.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/guid.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-
-/* TLS to keep dialog lock record (initialized by UA) */
-int pjsip_dlg_lock_tls_id;
-
-struct dialog_lock_data
-{
- struct dialog_lock_data *prev;
- pjsip_dlg *dlg;
- int is_alive;
-};
-
-/*
- * Static function prototypes.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
- pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq );
-static int dlg_on_all_state_pre( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_all_state_post( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_null( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_incoming( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_calling( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding_caller( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_proceeding_callee( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_connecting( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_established( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_disconnected( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-static int dlg_on_state_terminated( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-
-/*
- * Dialog state handlers.
- */
-static int (*dlg_state_handlers[])(struct pjsip_dlg *, pjsip_transaction *,
- pjsip_event *) =
-{
- &dlg_on_state_null,
- &dlg_on_state_incoming,
- &dlg_on_state_calling,
- &dlg_on_state_proceeding,
- &dlg_on_state_connecting,
- &dlg_on_state_established,
- &dlg_on_state_disconnected,
- &dlg_on_state_terminated,
-};
-
-/*
- * Dialog state names.
- */
-static const char* dlg_state_names[] =
-{
- "STATE_NULL",
- "STATE_INCOMING",
- "STATE_CALLING",
- "STATE_PROCEEDING",
- "STATE_CONNECTING",
- "STATE_ESTABLISHED",
- "STATE_DISCONNECTED",
- "STATE_TERMINATED",
-};
-
-
-/*
- * Get the dialog string state, normally for logging purpose.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state)
-{
- return dlg_state_names[state];
-}
-
-/* Lock dialog mutex. */
-static void lock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
- struct dialog_lock_data *prev;
-
- pj_mutex_lock(dlg->mutex);
- prev = pj_thread_local_get(pjsip_dlg_lock_tls_id);
- lck->prev = prev;
- lck->dlg = dlg;
- lck->is_alive = 1;
- pj_thread_local_set(pjsip_dlg_lock_tls_id, lck);
-}
-
-/* Carefully unlock dialog mutex, protect against situation when the dialog
- * has already been destroyed.
- */
-static pj_status_t unlock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
- pj_assert(pj_thread_local_get(pjsip_dlg_lock_tls_id) == lck);
- pj_assert(dlg == lck->dlg);
-
- pj_thread_local_set(pjsip_dlg_lock_tls_id, lck->prev);
- if (lck->is_alive)
- pj_mutex_unlock(dlg->mutex);
-
- return lck->is_alive ? 0 : -1;
-}
-
-/*
- * This is called by dialog's FSM to change dialog's state.
- */
-static void dlg_set_state( pjsip_dlg *dlg, pjsip_dlg_state_e state,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event);
-
- PJ_LOG(4, (dlg->obj_name, "State %s-->%s (ev=%s, src=%s, data=%p)",
- pjsip_dlg_state_str(dlg->state), pjsip_dlg_state_str(state),
- event ? pjsip_event_str(event->type) : "",
- event ? pjsip_event_str(event->src_type) : "",
- event ? event->src.data : NULL));
-
- dlg->state = state;
- dlg->handle_tsx_event = dlg_state_handlers[state];
-}
-
-/*
- * Invoke dialog's callback.
- * This function is called by dialog's FSM, and interpret the event and call
- * the corresponding callback registered by application.
- */
-static void dlg_call_dlg_callback( pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
- pjsip_event *event )
-{
- pjsip_dlg_callback *cb = dlg->ua->dlg_cb;
- if (!cb) {
- PJ_LOG(4,(dlg->obj_name, "Can not call callback (none registered)."));
- return;
- }
-
- /* Low level event: call the all-events callback. */
- if (cb->on_all_events) {
- (*cb->on_all_events)(dlg, dlg_event, event);
- }
-
- /* Low level event: call the tx/rx callback if this is a tx/rx event. */
- if (event->type == PJSIP_EVENT_BEFORE_TX && cb->on_before_tx)
- {
- (*cb->on_before_tx)(dlg, event->obj.tsx, event->src.tdata, event->data.long_data);
- }
- else if (event->type == PJSIP_EVENT_TX_MSG &&
- event->src_type == PJSIP_EVENT_TX_MSG && cb->on_tx_msg)
- {
- (*cb->on_tx_msg)(dlg, event->obj.tsx, event->src.tdata);
- }
- else if (event->type == PJSIP_EVENT_RX_MSG &&
- event->src_type == PJSIP_EVENT_RX_MSG && cb->on_rx_msg) {
- (*cb->on_rx_msg)(dlg, event->obj.tsx, event->src.rdata);
- }
-
- /* Now trigger high level events.
- * High level event should only occurs when dialog's state has changed,
- * except for on_provisional, which may be called multiple times whenever
- * response message is sent
- */
- if (dlg->state == PJSIP_DIALOG_STATE_PROCEEDING &&
- (event->type== PJSIP_EVENT_TSX_STATE_CHANGED) &&
- event->obj.tsx == dlg->invite_tsx)
- {
- /* Sent/received provisional responses. */
- if (cb->on_provisional)
- (*cb->on_provisional)(dlg, event->obj.tsx, event);
- }
-
- if (dlg_event == PJSIP_DIALOG_EVENT_MID_CALL_REQUEST) {
- if (cb->on_mid_call_events)
- (*cb->on_mid_call_events)(dlg, event);
- return;
- }
-
- if (dlg_event != PJSIP_DIALOG_EVENT_STATE_CHANGED)
- return;
-
- if (dlg->state == PJSIP_DIALOG_STATE_INCOMING) {
-
- /* New incoming dialog. */
- pj_assert (event->src_type == PJSIP_EVENT_RX_MSG);
- (*cb->on_incoming)(dlg, event->obj.tsx, event->src.rdata);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_CALLING) {
-
- /* Dialog has just sent the first INVITE. */
- if (cb->on_calling) {
- (*cb->on_calling)(dlg, event->obj.tsx, event->src.tdata);
- }
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_DISCONNECTED) {
-
- if (cb->on_disconnected)
- (*cb->on_disconnected)(dlg, event);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_TERMINATED) {
-
- if (cb->on_terminated)
- (*cb->on_terminated)(dlg);
-
- pjsip_ua_destroy_dialog(dlg);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_CONNECTING) {
-
- if (cb->on_connecting)
- (*cb->on_connecting)(dlg, event);
-
- } else if (dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
-
- if (cb->on_established)
- (*cb->on_established)(dlg, event);
- }
-}
-
-/*
- * This callback receives event from the transaction layer (via User Agent),
- * or from dialog timer (for 200/INVITE or ACK retransmission).
- */
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int status = 0;
- struct dialog_lock_data lck;
-
- PJ_LOG(4, (dlg->obj_name, "state=%s (evt=%s, src=%s)",
- pjsip_dlg_state_str(dlg->state),
- pjsip_event_str(event->type),
- pjsip_event_str(event->src_type)));
-
-
- lock_dialog(dlg, &lck);
-
- status = dlg_on_all_state_pre( dlg, tsx, event);
-
- if (status==0) {
- status = (*dlg->handle_tsx_event)(dlg, tsx, event);
- }
- if (status==0) {
- status = dlg_on_all_state_post( dlg, tsx, event);
- }
-
- unlock_dialog(dlg, &lck);
-}
-
-/*
- * This function contains common processing in all states, and it is called
- * before the FSM is invoked.
- */
-static int dlg_on_all_state_pre( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event)
-
- if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED)
- return 0;
-
- if (tsx && (tsx->state==PJSIP_TSX_STATE_CALLING ||
- tsx->state==PJSIP_TSX_STATE_TRYING))
- {
- ++dlg->pending_tsx_count;
-
- } else if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED)
- {
- --dlg->pending_tsx_count;
- if (tsx == dlg->invite_tsx)
- dlg->invite_tsx = NULL;
- }
-
- if (tsx->method.id == PJSIP_INVITE_METHOD) {
- tsx->handle_ack = 1;
- }
- return 0;
-}
-
-
-/*
- * This function contains common processing in all states, and it is called
- * after the FSM is invoked.
- */
-static int dlg_on_all_state_post( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(event)
-
- if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) {
- if (dlg->pending_tsx_count == 0 &&
- dlg->state != PJSIP_DIALOG_STATE_CONNECTING &&
- dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED &&
- dlg->state != PJSIP_DIALOG_STATE_TERMINATED)
- {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/*
- * Internal function to initialize dialog, contains common initialization
- * for both UAS and UAC dialog.
- */
-static pj_status_t dlg_init( pjsip_dlg *dlg )
-{
- /* Init mutex. */
- dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
- if (!dlg->mutex) {
- PJ_PERROR((dlg->obj_name, "pj_mutex_create()"));
- return -1;
- }
-
- /* Init route-set (Initially empty) */
- pj_list_init(&dlg->route_set);
-
- /* Init auth credential list. */
- pj_list_init(&dlg->auth_sess);
-
- return PJ_SUCCESS;
-}
-
-/*
- * This one is called just before dialog is destroyed.
- * It is called while mutex is held.
- */
-PJ_DEF(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg )
-{
- struct dialog_lock_data *lck;
-
- //PJ_TODO(CHECK_THIS);
- pj_assert(dlg->pending_tsx_count == 0);
-
- /* Mark dialog as dead. */
- lck = pj_thread_local_get(pjsip_dlg_lock_tls_id);
- while (lck) {
- if (lck->dlg == dlg)
- lck->is_alive = 0;
- lck = lck->prev;
- }
-}
-
-/*
- * Initialize dialog from the received request.
- * This is an internal function which is called by the User Agent (sip_ua.c),
- * and it will initialize most of dialog's properties with values from the
- * received message.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg, pjsip_rx_data *rdata )
-{
- pjsip_msg *msg = rdata->msg;
- pjsip_to_hdr *to;
- pjsip_contact_hdr *contact;
- pjsip_name_addr *name_addr;
- pjsip_sip_uri *url;
- unsigned flag;
- pjsip_event event;
-
- pj_assert(dlg && rdata);
-
- PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p)", rdata));
-
- /* Must be an INVITE request. */
- pj_assert(msg->type == PJSIP_REQUEST_MSG &&
- msg->line.req.method.id == PJSIP_INVITE_METHOD);
-
- /* Init general dialog data. */
- if (dlg_init(dlg) != PJ_SUCCESS) {
- return -1;
- }
-
- /* Get the To header. */
- to = rdata->to;
-
- /* Copy URI in the To header as our local URI. */
- dlg->local.info = pjsip_hdr_clone( dlg->pool, to);
-
- /* Set tag in the local info. */
- dlg->local.info->tag = dlg->local.tag;
-
- /* Create local Contact to be advertised in the response.
- * At the moment, just copy URI from the local URI as our contact.
- */
- dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->local.contact->star = 0;
- name_addr = (pjsip_name_addr *)dlg->local.info->uri;
- dlg->local.contact->uri = (pjsip_uri*) name_addr;
- url = (pjsip_sip_uri*) name_addr->uri;
- //url->port = rdata->via->sent_by.port;
- //url->port = pj_sockaddr_get_port( pjsip_transport_get_local_addr(rdata->transport) );
-
- /* Save remote URI. */
- dlg->remote.info = pjsip_hdr_clone( dlg->pool, rdata->from );
- pjsip_fromto_set_to( dlg->remote.info );
- pj_strdup( dlg->pool, &dlg->remote.tag, &rdata->from->tag );
-
- /* Save remote Contact. */
- contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
- } else {
- PJ_LOG(3,(dlg->obj_name, "No Contact header in INVITE from %s",
- pj_sockaddr_get_str_addr(&rdata->addr)));
- dlg->remote.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->remote.contact->uri = dlg->remote.info->uri;
- }
-
- /* Save Call-ID. */
- dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
- pj_strdup( dlg->pool, &dlg->call_id->id, &rdata->call_id );
-
- /* Initialize local CSeq and save remote CSeq.*/
- dlg->local.cseq = rdata->timestamp.sec & 0xFFFF;
- dlg->remote.cseq = rdata->cseq->cseq;
-
- /* Secure? */
- flag = pjsip_transport_get_flag(rdata->transport);
- dlg->secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
-
- /* Initial state is NULL. */
- event.type = event.src_type = PJSIP_EVENT_RX_MSG;
- event.src.rdata = rdata;
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
- PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p) complete", rdata));
- return PJ_SUCCESS;
-}
-
-/*
- * Set the contact details.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
- const pj_str_t *contact )
-{
- pjsip_uri *local_uri;
- pj_str_t tmp;
-
- pj_strdup_with_null(dlg->pool, &tmp, contact);
- local_uri = pjsip_parse_uri( dlg->pool, tmp.ptr, tmp.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (local_uri == NULL) {
- PJ_LOG(2, (dlg->obj_name, "set_contact: invalid URI"));
- return -1;
- }
-
- dlg->local.contact->star = 0;
- dlg->local.contact->uri = local_uri;
- return 0;
-}
-
-/*
- * Set route set.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
- const pjsip_route_hdr *route_set )
-{
- pjsip_route_hdr *hdr;
-
- pj_list_init(&dlg->route_set);
- hdr = route_set->next;
- while (hdr != route_set) {
- pjsip_route_hdr *cloned = pjsip_hdr_clone(dlg->pool, hdr);
- pj_list_insert_before( &dlg->route_set, cloned);
- hdr = hdr->next;
- }
- return 0;
-}
-
-/*
- * Set route set without cloning the header.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
- pjsip_route_hdr *route_set)
-{
- pjsip_route_hdr *hdr;
-
- pj_list_init(&dlg->route_set);
- hdr = route_set->next;
- while (hdr != route_set) {
- pj_list_insert_before( &dlg->route_set, hdr);
- hdr = hdr->next;
- }
- return 0;
-}
-
-/*
- * Application calls this function when it wants to initiate an outgoing
- * dialog (incoming dialogs are created automatically by UA when it receives
- * INVITE, by calling pjsip_dlg_init_from_rdata()).
- * This function should initialize most of the dialog's properties.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
- const pj_str_t *c_local_info,
- const pj_str_t *c_remote_info,
- const pj_str_t *c_target)
-{
- pj_time_val tv;
- pjsip_event event;
- pj_str_t buf;
-
- if (!dlg || !c_local_info || !c_remote_info) {
- pj_assert(dlg && c_local_info && c_remote_info);
- return -1;
- }
-
- PJ_LOG(5, (dlg->obj_name, "initializing"));
-
- /* Init general dialog */
- if (dlg_init(dlg) != PJ_SUCCESS) {
- return -1;
- }
-
- /* Duplicate local info. */
- pj_strdup_with_null( dlg->pool, &buf, c_local_info);
-
- /* Build local URI. */
- dlg->local.target = pjsip_parse_uri(dlg->pool, buf.ptr, buf.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (dlg->local.target == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid local URI %s", buf.ptr));
- return -1;
- }
-
- /* Set local URI. */
- dlg->local.info = pjsip_from_hdr_create(dlg->pool);
- dlg->local.info->uri = dlg->local.target;
- dlg->local.info->tag = dlg->local.tag;
-
- /* Create local Contact to be advertised in the response. */
- dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
- dlg->local.contact->star = 0;
- dlg->local.contact->uri = dlg->local.target;
-
- /* Set remote URI. */
- dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
-
- /* Duplicate to buffer. */
- pj_strdup_with_null( dlg->pool, &buf, c_remote_info);
-
- /* Build remote info. */
- dlg->remote.info->uri = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (dlg->remote.info->uri == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid remote URI %s", buf.ptr));
- return -1;
- }
-
- /* Set remote Contact initially equal to the remote URI. */
- dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
- dlg->remote.contact->star = 0;
- dlg->remote.contact->uri = dlg->remote.info->uri;
-
- /* Set initial remote target. */
- if (c_target != NULL) {
- pj_strdup_with_null( dlg->pool, &buf, c_target);
- dlg->remote.target = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen, 0);
- if (dlg->remote.target == NULL) {
- PJ_LOG(2, (dlg->obj_name,
- "pjsip_dlg_init: invalid remote target %s", buf.ptr));
- return -1;
- }
- } else {
- dlg->remote.target = dlg->remote.info->uri;
- }
-
- /* Create globally unique Call-ID */
- dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
- pj_create_unique_string( dlg->pool, &dlg->call_id->id );
-
- /* Local and remote CSeq */
- pj_gettimeofday(&tv);
- dlg->local.cseq = tv.sec & 0xFFFF;
- dlg->remote.cseq = 0;
-
- /* Initial state is NULL. */
- event.type = event.src_type = PJSIP_EVENT_TX_MSG;
- event.src.data = NULL;
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
- /* Done. */
- PJ_LOG(4, (dlg->obj_name, "%s dialog initialized, From: %.*s, To: %.*s",
- pjsip_role_name(dlg->role),
- c_local_info->slen, c_local_info->ptr,
- c_remote_info->slen, c_remote_info->ptr));
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set credentials.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
- int count,
- const pjsip_cred_info *cred)
-{
- if (count > 0) {
- dlg->cred_info = pj_pool_alloc(dlg->pool, count * sizeof(pjsip_cred_info));
- pj_memcpy(dlg->cred_info, cred, count * sizeof(pjsip_cred_info));
- }
- dlg->cred_count = count;
- return 0;
-}
-
-/*
- * Create a new request within dialog (i.e. after the dialog session has been
- * established). The construction of such requests follows the rule in
- * RFC3261 section 12.2.1.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
- pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq )
-{
- pjsip_tx_data *tdata;
- pjsip_contact_hdr *contact;
- pjsip_route_hdr *route, *end_list;
-
- /* Contact Header field.
- * Contact can only be present in requests that establish dialog (in the
- * core SIP spec, only INVITE).
- */
- if (method->id == PJSIP_INVITE_METHOD)
- contact = dlg->local.contact;
- else
- contact = NULL;
-
- tdata = pjsip_endpt_create_request_from_hdr( dlg->ua->endpt,
- method,
- dlg->remote.target,
- dlg->local.info,
- dlg->remote.info,
- contact,
- dlg->call_id,
- cseq,
- NULL);
- if (!tdata) {
- PJ_THROW(1);
- return;
- }
-
- /* Just copy dialog route-set to Route header.
- * The transaction will do the processing as specified in Section 12.2.1
- * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
- */
- route = dlg->route_set.next;
- end_list = &dlg->route_set;
- for (; route != end_list; route = route->next ) {
- pjsip_route_hdr *r;
- r = pjsip_hdr_shallow_clone( tdata->pool, route );
- pjsip_routing_hdr_set_route(r);
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
- }
-
- /* Copy authorization headers. */
- pjsip_auth_init_req( dlg->pool, tdata, &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info);
-
- *p_tdata = tdata;
-}
-
-
-/*
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
- const pjsip_method *method,
- int cseq)
-{
- PJ_USE_EXCEPTION;
- struct dialog_lock_data lck;
- pjsip_tx_data *tdata = NULL;
-
- pj_assert(dlg != NULL && method != NULL);
- if (!dlg || !method) {
- return NULL;
- }
-
- PJ_LOG(5, (dlg->obj_name, "Creating request"));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Use outgoing CSeq and increment it by one. */
- if (cseq < 0)
- cseq = dlg->local.cseq + 1;
-
- PJ_LOG(5, (dlg->obj_name, "creating request %.*s cseq=%d",
- method->name.slen, method->name.ptr, cseq));
-
- /* Create the request. */
- PJ_TRY {
- dlg_create_request_throw(&tdata, dlg, method, cseq);
- PJ_LOG(5, (dlg->obj_name, "request data %s created", tdata->obj_name));
- }
- PJ_CATCH_ANY {
- /* Failed! Delete transmit data. */
- if (tdata) {
- pjsip_tx_data_dec_ref( tdata );
- tdata = NULL;
- }
- }
- PJ_END;
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * Sends request.
- * Select the transport for the request message
- */
-static pj_status_t dlg_send_request( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
- pjsip_transaction *tsx;
- pj_status_t status = PJ_SUCCESS;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL && tdata != NULL);
- if (!dlg || !tdata) {
- return -1;
- }
-
- PJ_LOG(5, (dlg->obj_name, "sending request %s", tdata->obj_name));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Create a new transaction. */
- tsx = pjsip_endpt_create_tsx( dlg->ua->endpt );
- if (!tsx) {
- unlock_dialog(dlg, &lck);
- return -1;
- }
-
- PJ_LOG(4, (dlg->obj_name, "Created new UAC transaction: %s", tsx->obj_name));
-
- /* Initialize transaction */
- tsx->module_data[dlg->ua->mod_id] = dlg;
- status = pjsip_tsx_init_uac( tsx, tdata );
- if (status != PJ_SUCCESS) {
- unlock_dialog(dlg, &lck);
- pjsip_endpt_destroy_tsx( dlg->ua->endpt, tsx );
- return -1;
- }
- pjsip_endpt_register_tsx( dlg->ua->endpt, tsx );
-
- /* Start the transaction. */
- pjsip_tsx_on_tx_msg(tsx, tdata);
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return status;
-}
-
-/*
- * This function can be called by application to send ANY outgoing message
- * to remote party.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
- pj_status_t status;
- int tsx_status;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL && tdata != NULL);
- if (!dlg || !tdata) {
- return -1;
- }
-
- lock_dialog(dlg, &lck);
-
- if (tdata->msg->type == PJSIP_REQUEST_MSG) {
- int request_cseq;
- pjsip_msg *msg = tdata->msg;
- pjsip_cseq_hdr *cseq_hdr;
-
- switch (msg->line.req.method.id) {
- case PJSIP_CANCEL_METHOD:
-
- /* Check the INVITE transaction state. */
- tsx_status = dlg->invite_tsx->status_code;
- if (tsx_status >= 200) {
- /* Already terminated. Can't cancel. */
- status = -1;
- goto on_return;
- }
-
- /* If we've got provisional response, then send CANCEL and wait for
- * the response to INVITE to arrive. Otherwise just send CANCEL and
- * terminate the INVITE.
- */
- if (tsx_status < 100) {
- pjsip_tsx_terminate( dlg->invite_tsx,
- PJSIP_SC_REQUEST_TERMINATED);
- status = 0;
- goto on_return;
- }
-
- status = 0;
- request_cseq = dlg->invite_tsx->cseq;
- break;
-
- case PJSIP_ACK_METHOD:
- /* Sending ACK outside of transaction is not supported at present! */
- pj_assert(0);
- status = 0;
- request_cseq = dlg->local.cseq;
- break;
-
- case PJSIP_INVITE_METHOD:
- /* For an initial INVITE, reset dialog state to NULL so we get
- * 'normal' UAC notifications such as on_provisional(), etc.
- * Initial INVITE is the request that is sent when the dialog has
- * not been established yet. It's not necessarily the first INVITE
- * sent, as when the Authorization fails, subsequent INVITE are also
- * considered as an initial INVITE.
- */
- if (dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
- /* Set state to NULL. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, NULL);
-
- } else {
- /* This is a re-INVITE */
- }
- status = 0;
- request_cseq = dlg->local.cseq + 1;
- break;
-
- default:
- status = 0;
- request_cseq = dlg->local.cseq + 1;
- break;
- }
-
- if (status != 0)
- goto on_return;
-
- /* Update dialog's local CSeq, if necessary. */
- if (request_cseq != dlg->local.cseq)
- dlg->local.cseq = request_cseq;
-
- /* Update CSeq header in the request. */
- cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
- PJSIP_H_CSEQ, NULL);
- pj_assert(cseq_hdr != NULL);
-
- /* Update the CSeq */
- cseq_hdr->cseq = request_cseq;
-
- /* Force the whole message to be re-printed. */
- pjsip_tx_data_invalidate_msg( tdata );
-
- /* Now send the request. */
- status = dlg_send_request(dlg, tdata);
-
- } else {
- /*
- * This is only valid for sending response to INVITE!
- */
- pjsip_cseq_hdr *cseq_hdr;
-
- if (dlg->invite_tsx == NULL || dlg->invite_tsx->status_code >= 200) {
- status = -1;
- goto on_return;
- }
-
- cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
- PJSIP_H_CSEQ, NULL);
- pj_assert(cseq_hdr);
-
- if (cseq_hdr->method.id != PJSIP_INVITE_METHOD) {
- status = -1;
- goto on_return;
- }
-
- pj_assert(cseq_hdr->cseq == dlg->invite_tsx->cseq);
-
- pjsip_tsx_on_tx_msg(dlg->invite_tsx, tdata);
- status = 0;
- }
-
-on_return:
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- /* Whatever happen delete the message. */
- pjsip_tx_data_dec_ref( tdata );
-
- return status;
-}
-
-/*
- * Sends outgoing invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg )
-{
- pjsip_method method;
- struct dialog_lock_data lck;
- const pjsip_allow_hdr *allow_hdr;
- pjsip_tx_data *tdata;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to send invitation"));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Create request. */
- pjsip_method_set( &method, PJSIP_INVITE_METHOD);
- tdata = pjsip_dlg_create_request( dlg, &method, -1 );
- if (tdata == NULL) {
- unlock_dialog(dlg, &lck);
- return NULL;
- }
-
- /* Invite SHOULD contain "Allow" header. */
- allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
- if (allow_hdr) {
- pjsip_msg_add_hdr( tdata->msg,
- pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
- }
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * Cancel pending outgoing dialog invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg )
-{
- pjsip_tx_data *tdata = NULL;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to cancel invitation"));
-
- lock_dialog(dlg, &lck);
-
- /* Check the INVITE transaction. */
- if (dlg->invite_tsx == NULL || dlg->role != PJSIP_ROLE_UAC) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
- "no INVITE transaction found"));
- goto on_return;
- }
-
- /* Construct the CANCEL request. */
- tdata = pjsip_endpt_create_cancel( dlg->ua->endpt,
- dlg->invite_tsx->last_tx );
- if (tdata == NULL) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
- "unable to construct request"));
- goto on_return;
- }
-
- /* Add reference counter to tdata. */
- pjsip_tx_data_add_ref(tdata);
-
-on_return:
- unlock_dialog(dlg, &lck);
- return tdata;
-}
-
-
-/*
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )
-{
- pjsip_tx_data *tdata = NULL;
- pjsip_msg *msg;
- struct dialog_lock_data lck;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "pjsip_dlg_answer: code=%d", code));
-
- /* Lock dialog. */
- lock_dialog(dlg, &lck);
-
- /* Must have pending INVITE. */
- if (dlg->invite_tsx == NULL) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: no INVITE transaction found"));
- goto on_return;
- }
- /* Must be UAS. */
- if (dlg->role != PJSIP_ROLE_UAS) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: not UAS"));
- goto on_return;
- }
- /* Must have not answered with final response before. */
- if (dlg->invite_tsx->status_code >= 200) {
- PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: transaction already terminated "
- "with status %d", dlg->invite_tsx->status_code));
- goto on_return;
- }
-
- /* Get transmit data and the message.
- * We will rewrite the message with a new status code.
- */
- only if tdata is not pending!!!
- tdata = dlg->invite_tsx->last_tx;
- msg = tdata->msg;
-
- /* Set status code and reason phrase. */
- if (code < 100 || code >= 700) code = 500;
- msg->line.status.code = code;
- msg->line.status.reason = *pjsip_get_status_text(code);
-
- /* For 2xx response, Contact and Record-Route must be added. */
- if (PJSIP_IS_STATUS_IN_CLASS(code,200)) {
- const pjsip_allow_hdr *allow_hdr;
-
- if (pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL) == NULL) {
- pjsip_contact_hdr *contact;
- contact = pjsip_hdr_shallow_clone( tdata->pool, dlg->local.contact);
- pjsip_msg_add_hdr( msg, (pjsip_hdr*)contact );
- }
-
- /* 2xx response MUST contain "Allow" header. */
- allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
- if (allow_hdr) {
- pjsip_msg_add_hdr( msg, pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
- }
- }
-
- /* for all but 100 responses, To-tag must be set. */
- if (code != 100) {
- pjsip_to_hdr *to;
- to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL);
- to->tag = dlg->local.tag;
- }
-
- /* Reset packet buffer. */
- pjsip_tx_data_invalidate_msg(tdata);
-
- /* Add reference counter */
- pjsip_tx_data_add_ref(tdata);
-
-on_return:
-
- /* Unlock dialog. */
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-
-/*
- * Send BYE request to terminate the dialog's session.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg )
-{
- pjsip_method method;
- struct dialog_lock_data lck;
- pjsip_tx_data *tdata;
-
- if (!dlg) {
- pj_assert(dlg != NULL);
- return NULL;
- }
-
- PJ_LOG(4, (dlg->obj_name, "request to terminate session"));
-
- lock_dialog(dlg, &lck);
-
- pjsip_method_set( &method, PJSIP_BYE_METHOD);
- tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-
- unlock_dialog(dlg, &lck);
-
- return tdata;
-}
-
-/*
- * High level function to disconnect dialog's session. Depending on dialog's
- * state, this function will either send CANCEL, final response, or BYE to
- * trigger the disconnection. A status code must be supplied, which will be
- * sent if dialog will be transmitting a final response to INVITE.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg,
- int status_code )
-{
- pjsip_tx_data *tdata = NULL;
-
- pj_assert(dlg != NULL);
- if (!dlg) {
- return NULL;
- }
-
- switch (dlg->state) {
- case PJSIP_DIALOG_STATE_INCOMING:
- tdata = pjsip_dlg_answer(dlg, status_code);
- break;
-
- case PJSIP_DIALOG_STATE_CALLING:
- tdata = pjsip_dlg_cancel(dlg);
- break;
-
- case PJSIP_DIALOG_STATE_PROCEEDING:
- if (dlg->role == PJSIP_ROLE_UAC) {
- tdata = pjsip_dlg_cancel(dlg);
- } else {
- tdata = pjsip_dlg_answer(dlg, status_code);
- }
- break;
-
- case PJSIP_DIALOG_STATE_ESTABLISHED:
- tdata = pjsip_dlg_bye(dlg);
- break;
-
- default:
- PJ_LOG(4,(dlg->obj_name, "Invalid state %s in pjsip_dlg_disconnect()",
- dlg_state_names[dlg->state]));
- break;
- }
-
- return tdata;
-}
-
-/*
- * Handling of the receipt of 2xx/INVITE response.
- */
-static void dlg_on_recv_2xx_invite( pjsip_dlg *dlg,
- pjsip_event *event )
-{
- pjsip_msg *msg;
- pjsip_contact_hdr *contact;
- pjsip_hdr *hdr, *end_hdr;
- pjsip_method method;
- pjsip_tx_data *ack_tdata;
-
- /* Get the message */
- msg = event->src.rdata->msg;
-
- /* Update remote's tag information. */
- pj_strdup(dlg->pool, &dlg->remote.info->tag, &event->src.rdata->to_tag);
-
- /* Copy Contact information in the 2xx/INVITE response to dialog's.
- * remote contact
- */
- contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
- } else {
- /* duplicate contact from "From" header (?) */
- PJ_LOG(4,(dlg->obj_name, "Received 200/OK to INVITE with no Contact!"));
- dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
- dlg->remote.contact->uri = dlg->remote.info->uri;
- }
-
- /* Copy Record-Route header (in reverse order) as dialog's route-set,
- * overwriting previous route-set, if any, even if the received route-set
- * is empty.
- */
- pj_list_init(&dlg->route_set);
- end_hdr = &msg->hdr;
- for (hdr = msg->hdr.prev; hdr!=end_hdr; hdr = hdr->prev) {
- if (hdr->type == PJSIP_H_RECORD_ROUTE) {
- pjsip_route_hdr *r;
- r = pjsip_hdr_clone(dlg->pool, hdr);
- pjsip_routing_hdr_set_route(r);
- pj_list_insert_before(&dlg->route_set, r);
- }
- }
-
- /* On receipt of 200/INVITE response, send ACK.
- * This ack must be saved and retransmitted whenever we receive
- * 200/INVITE retransmission, until 64*T1 seconds elapsed.
- */
- pjsip_method_set( &method, PJSIP_ACK_METHOD);
- ack_tdata = pjsip_dlg_create_request( dlg, &method, dlg->invite_tsx->cseq);
- if (ack_tdata == NULL) {
- //PJ_TODO(HANDLE_CREATE_ACK_FAILURE)
- PJ_LOG(2, (dlg->obj_name, "Error sending ACK msg: can't create request"));
- return;
- }
-
- /* Send with the transaction. */
- pjsip_tsx_on_tx_ack( dlg->invite_tsx, ack_tdata);
-
- /* Decrement reference counter because pjsip_dlg_create_request
- * automatically increments the request.
- */
- pjsip_tx_data_dec_ref( ack_tdata );
-}
-
-/*
- * State NULL, before any events have been received.
- */
-static int dlg_on_state_null( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG)
- {
- pjsip_hdr *hdr, *hdr_list;
-
- pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
- /* Save the INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Change state to INCOMING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_INCOMING, event);
-
- /* Create response buffer. */
- tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 100);
- pjsip_tx_data_add_ref(tsx->last_tx);
-
- /* Copy the Record-Route headers into dialog's route_set, maintaining
- * the order.
- */
- pj_list_init(&dlg->route_set);
- hdr_list = &event->src.rdata->msg->hdr;
- hdr = hdr_list->next;
- while (hdr != hdr_list) {
- if (hdr->type == PJSIP_H_RECORD_ROUTE) {
- pjsip_route_hdr *route;
- route = pjsip_hdr_clone(dlg->pool, hdr);
- pjsip_routing_hdr_set_route(route);
- pj_list_insert_before(&dlg->route_set, route);
- }
- hdr = hdr->next;
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_TX_MSG)
- {
- pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
- /* Save the INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Change state to CALLING. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CALLING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-/*
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
-static int dlg_on_state_incoming( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- return dlg_on_state_proceeding_callee( dlg, tsx, event );
-}
-
-/*
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
-static int dlg_on_state_calling( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (tsx == dlg->invite_tsx) {
- return dlg_on_state_proceeding_caller( dlg, tsx, event );
- }
- return 0;
-}
-
-/*
- * State PROCEEDING is after provisional response is received.
- * Since the processing is similar to state CALLING, this function is also
- * called for CALLING state.
- */
-static int dlg_on_state_proceeding_caller( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int dlg_is_terminated = 0;
-
- /* We only care about our INVITE transaction.
- * Ignore other transaction progression (such as CANCEL).
- */
- if (tsx != dlg->invite_tsx) {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- return 0;
- }
-
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED) {
- switch (tsx->state) {
- case PJSIP_TSX_STATE_PROCEEDING:
- if (dlg->state != PJSIP_DIALOG_STATE_PROCEEDING) {
- /* Change state to PROCEEDING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- } else {
- /* Also notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- break;
-
- case PJSIP_TSX_STATE_COMPLETED:
- /* Change dialog state. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- /* Update remote target, take it from the contact hdr. */
- pjsip_contact_hdr *contact;
- contact = pjsip_msg_find_hdr(event->src.rdata->msg,
- PJSIP_H_CONTACT, NULL);
- if (contact) {
- dlg->remote.target = pjsip_uri_clone(dlg->pool, contact->uri);
- } else {
- PJ_LOG(4,(dlg->obj_name,
- "Warning: found no Contact hdr in 200/OK"));
- }
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
- } else if (tsx->status_code==401 || tsx->status_code==407) {
- /* Handle Authentication challenge. */
- pjsip_tx_data *tdata;
- tdata = pjsip_auth_reinit_req( dlg->ua->endpt,
- dlg->pool, &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info,
- tsx->last_tx, event->src.rdata);
- if (tdata) {
- /* Re-use original request, with a new transaction.
- * Need not to worry about CSeq, dialog will take care.
- */
- pjsip_dlg_send_msg(dlg, tdata);
- return 0;
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* Send ACK when dialog is connected. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- pj_assert(event->src_type == PJSIP_EVENT_RX_MSG);
- dlg_on_recv_2xx_invite(dlg, event);
- }
- break;
-
- case PJSIP_TSX_STATE_TERMINATED:
- /*
- * Transaction is terminated because of timeout or transport error.
- * To let the application go to normal state progression, call the
- * callback twice. First is to emulate disconnection, and then call
- * again (with state TERMINATED) to destroy the dialog.
- */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* The INVITE transaction will be destroyed, so release reference
- * to it.
- */
- dlg->invite_tsx = NULL;
-
- /* We should terminate the dialog now.
- * But it's possible that we have other pending transactions (for
- * example, outgoing CANCEL is in progress).
- * So destroy the dialog only if there's no other transaction.
- */
- if (dlg->pending_tsx_count == 0) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- dlg_is_terminated = 1;
- }
- break;
-
- default:
- pj_assert(0);
- break;
- }
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- return dlg_is_terminated ? -1 : 0;
-}
-
-/*
- * State PROCEEDING for UAS is after the callee send provisional response.
- * This function is also called for INCOMING state.
- */
-static int dlg_on_state_proceeding_callee( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- int dlg_is_terminated = 0;
-
- pj_assert( dlg->invite_tsx != NULL );
-
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_TX_MSG &&
- tsx == dlg->invite_tsx)
- {
- switch (tsx->state) {
- case PJSIP_TSX_STATE_PROCEEDING:
- /* Change state to PROCEEDING */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- break;
-
- case PJSIP_TSX_STATE_COMPLETED:
- case PJSIP_TSX_STATE_TERMINATED:
- /* Change dialog state. */
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
- } else {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* If transaction is terminated in non-2xx situation,
- * terminate dialog as well. This happens when something unexpected
- * occurs, such as transport error.
- */
- if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
- !PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200))
- {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- dlg_is_terminated = 1;
- }
- break;
-
- default:
- pj_assert(0);
- break;
- }
-
- } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->method.id == PJSIP_CANCEL_METHOD)
- {
- pjsip_tx_data *tdata;
-
- /* Check if sequence number matches the pending INVITE. */
- if (dlg->invite_tsx==NULL ||
- pj_strcmp(&tsx->branch, &dlg->invite_tsx->branch) != 0)
- {
- PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no matching INVITE"));
-
- /* No matching INVITE transaction found. */
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- PJSIP_SC_CALL_TSX_DOES_NOT_EXIST );
- pjsip_tsx_on_tx_msg(tsx, tdata);
- return 0;
- }
-
- /* Always respond the CANCEL with 200/CANCEL no matter what. */
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 200 );
- pjsip_tsx_on_tx_msg( tsx, tdata );
-
- /* Respond the INVITE transaction with 487, only if transaction has
- * not completed.
- */
- if (dlg->invite_tsx->last_tx) {
- if (dlg->invite_tsx->status_code < 200) {
- tdata = dlg->invite_tsx->last_tx;
- tdata->msg->line.status.code = 487;
- tdata->msg->line.status.reason = *pjsip_get_status_text(487);
- /* Reset packet buffer. */
- pjsip_tx_data_invalidate_msg(tdata);
- pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
- } else {
- PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no effect, "
- "Transaction already terminated "
- "with status %d",
- dlg->invite_tsx->status_code));
- }
- } else {
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 487);
- pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
- }
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return dlg_is_terminated ? -1 : 0;
-}
-
-static int dlg_on_state_proceeding( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (dlg->role == PJSIP_ROLE_UAC) {
- return dlg_on_state_proceeding_caller( dlg, tsx, event );
- } else {
- return dlg_on_state_proceeding_callee( dlg, tsx, event );
- }
-}
-
-static int dlg_on_state_connecting( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- if (tsx == dlg->invite_tsx) {
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- (tsx->state == PJSIP_TSX_STATE_TERMINATED ||
- tsx->state == PJSIP_TSX_STATE_COMPLETED ||
- tsx->state == PJSIP_TSX_STATE_CONFIRMED))
- {
- if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_ESTABLISHED, event);
- } else {
- /* Probably because we never get the ACK, or transport error
- * when sending ACK.
- */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
- }
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
- } else {
- /* Handle case when transaction is started when dialog is connecting
- * (e.g. BYE requests cross wire.
- */
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAS)
- {
- pjsip_tx_data *response;
-
- if (tsx->status_code >= 200)
- return 0;
-
- if (tsx->method.id == PJSIP_BYE_METHOD) {
- /* Set state to DISCONNECTED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- response = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 200);
- } else {
- response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- }
-
- if (response)
- pjsip_tsx_on_tx_msg(tsx, response);
-
- return 0;
- }
- }
- return 0;
-}
-
-static int dlg_on_state_established( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(tsx)
-
- if (tsx && tsx->method.id == PJSIP_BYE_METHOD) {
- /* Set state to DISCONNECTED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- /* Answer with 200/BYE. */
- if (event->src_type == PJSIP_EVENT_RX_MSG) {
- pjsip_tx_data *tdata;
- tdata = pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata,
- 200 );
- if (tdata)
- pjsip_tsx_on_tx_msg( tsx, tdata );
- }
- } else if (tsx && event->src_type == PJSIP_EVENT_RX_MSG) {
- pjsip_method_e method = event->src.rdata->cseq->method.id;
-
- PJ_TODO(PROPERLY_HANDLE_REINVITATION)
-
- /* Reinvitation. The message may be INVITE or an ACK. */
- if (method == PJSIP_INVITE_METHOD) {
- if (dlg->invite_tsx && dlg->invite_tsx->status_code < 200) {
- /* Section 14.2: A UAS that receives a second INVITE before it
- * sends the final response to a first INVITE with a lower
- * CSeq sequence number on the same dialog MUST return a 500
- * (Server Internal Error) response to the second INVITE and
- * MUST include a Retry-After header field with a randomly
- * chosen value of between 0 and 10 seconds.
- */
- pjsip_retry_after_hdr *hdr;
- pjsip_tx_data *tdata =
- pjsip_endpt_create_response(dlg->ua->endpt,
- event->src.rdata, 500);
-
- if (!tdata)
- return 0;
-
- /* Add Retry-After. */
- hdr = pjsip_retry_after_hdr_create(tdata->pool);
- hdr->ivalue = 9;
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
-
- /* Send. */
- pjsip_tsx_on_tx_msg(tsx, tdata);
-
- return 0;
- }
-
- /* Keep this as our current INVITE transaction. */
- dlg->invite_tsx = tsx;
-
- /* Create response buffer. */
- tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 100);
- pjsip_tx_data_add_ref(tsx->last_tx);
-
- }
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_MID_CALL_REQUEST, event);
-
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-static int dlg_on_state_disconnected( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(tsx)
-
- /* Handle case when transaction is started when dialog is disconnected
- * (e.g. BYE requests cross wire.
- */
- if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAS)
- {
- pjsip_tx_data *response = NULL;
-
- if (tsx->status_code >= 200)
- return 0;
-
- if (tsx->method.id == PJSIP_BYE_METHOD) {
- response = pjsip_endpt_create_response( dlg->ua->endpt,
- event->src.rdata, 200);
- } else {
- response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- }
- if (response)
- pjsip_tsx_on_tx_msg(tsx, response);
-
- return 0;
- }
- /* Handle case when outgoing BYE was rejected with 401/407 */
- else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
- event->src_type == PJSIP_EVENT_RX_MSG &&
- tsx->role == PJSIP_ROLE_UAC)
- {
- if (tsx->status_code==401 || tsx->status_code==407) {
- pjsip_tx_data *tdata;
- tdata = pjsip_auth_reinit_req( dlg->ua->endpt, dlg->pool,
- &dlg->auth_sess,
- dlg->cred_count, dlg->cred_info,
- tsx->last_tx, event->src.rdata);
- if (tdata) {
- pjsip_dlg_send_msg(dlg, tdata);
- }
- }
- }
-
-
- if (dlg->pending_tsx_count == 0) {
- /* Set state to TERMINATED. */
- dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-
- /* Notify application. */
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
- return -1;
- } else {
- dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
- }
-
- return 0;
-}
-
-static int dlg_on_state_terminated( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event)
-{
- PJ_UNUSED_ARG(dlg)
- PJ_UNUSED_ARG(tsx)
- PJ_UNUSED_ARG(event)
-
- return -1;
-}
-
diff --git a/pjsip/src/pjsip-ua/sip_ua.c b/pjsip/src/pjsip-ua/sip_ua.c
deleted file mode 100644
index ac0980f5..00000000
--- a/pjsip/src/pjsip-ua/sip_ua.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_util.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_transaction.h>
-#include <pj/list.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/hash.h>
-#include <pj/pool.h>
-
-#define PJSIP_POOL_LEN_USER_AGENT 1024
-#define PJSIP_POOL_INC_USER_AGENT 0
-
-
-#define LOG_THIS "useragent.."
-
-/*
- * Static prototypes.
- */
-static pj_status_t ua_load(pjsip_endpoint *endpt);
-static pj_status_t ua_unload(void);
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *evt );
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua,
- pjsip_rx_data *rdata );
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
- pj_str_t *key );
-PJ_DECL(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg );
-
-/*
- * Module interface.
- */
-static struct user_agent
-{
- pjsip_module mod;
- pj_pool_t *pool;
- pjsip_endpoint *endpt;
- pj_mutex_t *mutex;
- pj_hash_table_t *dlg_table;
- pjsip_dialog dlg_list;
-
-} mod_ua =
-{
- {
- NULL, NULL, /* prev, next. */
- { "mod-ua", 6 }, /* Name. */
- -1, /* Id */
- PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
- NULL, /* User data. */
- 0, /* Number of methods supported. */
- { 0 }, /* Array of methods */
- &ua_load, /* load() */
- NULL, /* start() */
- NULL, /* stop() */
- &ua_unload, /* unload() */
- NULL, /* on_rx_request() */
- NULL, /* on_rx_response() */
- NULL, /* on_tx_request. */
- NULL, /* on_tx_response() */
- NULL, /* on_tsx_state() */
- }
-};
-
-/*
- * Initialize user agent instance.
- */
-static pj_status_t ua_load( pjsip_endpoint *endpt )
-{
- extern int pjsip_dlg_lock_tls_id; /* defined in sip_dialog.c */
- pj_status_t status;
-
- /* Initialize the user agent. */
- mod_ua.endpt = endpt;
- status = pjsip_endpt_create_pool( endpt, "pua%p", PJSIP_POOL_LEN_UA,
- PJSIP_POOL_INC_UA, &mod_ua.pool);
- if (status != PJ_SUCCESS)
- return status;
-
- status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
- if (status != PJ_SUCCESS)
- return status;
-
- mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
- if (ua->dlg_table == NULL)
- return PJ_ENOMEM;
-
- pj_list_init(&mod_ua.dlg_list);
-
- /* Initialize dialog lock. */
- pjsip_dlg_lock_tls_id = pj_thread_local_alloc();
- if (pjsip_dlg_lock_tls_id == -1) {
- return -1;
- }
- pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
-
- return PJ_SUCCESS;
-}
-
-/*
- * Destroy user agent.
- */
-static pj_status_t ua_unload()
-{
- pj_mutex_unlock(mod_ua.mutex);
-
- /* Release pool */
- if (mod_ua.pool) {
- pjsip_endpt_destroy_pool( mod_ua.endpt, mod_ua.pool );
- }
- return PJ_SUCCESS;
-}
-
-/*
- * Find dialog.
- * This function is called for a new transactions, which a dialog hasn't been
- * 'attached' to the transaction.
- */
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua, pjsip_rx_data *rdata )
-{
- pjsip_dlg *dlg;
- pj_str_t *tag;
-
- /* Non-CANCEL requests/response can be found by looking at the tag in the
- * hash table. CANCEL requests don't have tags, so instead we'll try to
- * find the UAS INVITE transaction in endpoint's hash table
- */
- if (rdata->cseq->method.id == PJSIP_CANCEL_METHOD) {
-
- /* Create key for the rdata, but this time, use INVITE as the
- * method.
- */
- pj_str_t key;
- pjsip_role_e role;
- pjsip_method invite_method;
- pjsip_transaction *invite_tsx;
-
- if (rdata->msg->type == PJSIP_REQUEST_MSG) {
- role = PJSIP_ROLE_UAS;
- } else {
- role = PJSIP_ROLE_UAC;
- }
- pjsip_method_set(&invite_method, PJSIP_INVITE_METHOD);
- pjsip_tsx_create_key(rdata->pool, &key, role, &invite_method, rdata);
-
- /* Lookup the INVITE transaction */
- invite_tsx = pjsip_endpt_find_tsx(ua->endpt, &key);
-
- /* We should find the dialog attached to the INVITE transaction */
- return invite_tsx ?
- (pjsip_dlg*) invite_tsx->module_data[ua->mod_id] : NULL;
-
- } else {
- if (rdata->msg->type == PJSIP_REQUEST_MSG) {
- tag = &rdata->to_tag;
- } else {
- tag = &rdata->from_tag;
- }
- /* Find the dialog in UA hash table */
- pj_mutex_lock(ua->mutex);
- dlg = pj_hash_get( ua->dlg_table, tag->ptr, tag->slen );
- pj_mutex_unlock(ua->mutex);
- }
-
- return dlg;
-}
-
-/*
- * This function receives event notification from transactions. It is called by
- * endpoint.
- */
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
- pjsip_user_agent *ua = mod->mod_data;
- pjsip_dlg *dlg = NULL;
- pjsip_transaction *tsx = event->obj.tsx;
-
- PJ_LOG(5, (LOG_THIS, "ua_tsx_handler(tsx=%s, evt=%s, src=%s, data=%p)",
- (tsx ? tsx->obj_name : "NULL"), pjsip_event_str(event->type),
- pjsip_event_str(event->src_type), event->src.data));
-
- /* Special case to handle ACK which doesn't match any INVITE transactions. */
- if (event->type == PJSIP_EVENT_RX_ACK_MSG) {
- /* Find the dialog based on the "tag". */
- dlg = find_dialog( ua, event->src.rdata );
-
- /* We should be able to find it. */
- if (!dlg) {
- PJ_LOG(4,(LOG_THIS, "Unable to find dialog for incoming ACK"));
- return;
- }
-
- /* Match CSeq with pending INVITE in dialog. */
- if (dlg->invite_tsx && dlg->invite_tsx->cseq==event->src.rdata->cseq->cseq) {
- /* A match found. */
- tsx = dlg->invite_tsx;
-
- /* Pass the event to transaction if transaction handles ACK. */
- if (tsx->handle_ack) {
- PJ_LOG(4,(LOG_THIS, "Re-routing strandled ACK to transaction"));
- pjsip_tsx_on_rx_msg(tsx, event->src.rdata);
- return;
- }
- } else {
- tsx = NULL;
- PJ_LOG(4,(LOG_THIS, "Unable to find INVITE tsx for incoming ACK"));
- return;
- }
- }
-
- /* For discard event, transaction is NULL. */
- if (tsx == NULL) {
- return;
- }
-
- /* Try to pickup the dlg from the transaction. */
- dlg = (pjsip_dlg*) tsx->module_data[ua->mod_id];
-
- if (dlg != NULL) {
-
- /* Nothing to do now. */
-
- } else if (event->src_type == PJSIP_EVENT_RX_MSG) {
-
- /* This must be a new UAS transaction. */
-
- /* Finds dlg that can handle this transaction. */
- dlg = find_dialog( ua, event->src.rdata);
-
- /* Create a new dlg if there's no existing dlg that can handle
- the request, ONLY if the incoming message is an INVITE request.
- */
- if (dlg==NULL && event->src.rdata->msg->type == PJSIP_REQUEST_MSG) {
-
- if (event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
- /* Create new dialog. */
- dlg = pjsip_ua_create_dialog( ua, PJSIP_ROLE_UAS );
-
- if (dlg == NULL ||
- pjsip_dlg_init_from_rdata( dlg, event->src.rdata) != 0)
- {
- pjsip_tx_data *tdata;
-
- /* Dialog initialization has failed. Respond request with 500 */
- if (dlg) {
- pjsip_ua_destroy_dialog(dlg);
- }
- tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata,
- PJSIP_SC_INTERNAL_SERVER_ERROR);
- if (tdata) {
- pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
- }
- return;
- }
-
- } else {
- pjsip_tx_data *tdata;
-
- /* Check the method */
- switch (tsx->method.id) {
- case PJSIP_INVITE_METHOD:
- case PJSIP_ACK_METHOD:
- case PJSIP_BYE_METHOD:
- case PJSIP_CANCEL_METHOD:
- /* Stale non-INVITE request.
- * For now, respond all stale requests with 481 (?).
- */
- tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata,
- PJSIP_SC_CALL_TSX_DOES_NOT_EXIST);
- if (tdata) {
- pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
- }
- break;
- }
-
- return;
- }
- } else {
- /* Check the method */
- switch (tsx->method.id) {
- case PJSIP_INVITE_METHOD:
- case PJSIP_ACK_METHOD:
- case PJSIP_BYE_METHOD:
- case PJSIP_CANCEL_METHOD:
- /* These methods belongs to dialog.
- * If we receive these methods while no dialog is found,
- * then it must be a stale responses.
- */
- break;
- default:
- return;
- }
-
- }
-
- if (dlg == NULL) {
- PJ_LOG(3, (LOG_THIS, "Receives spurious rdata %p from %s:%d",
- event->src.rdata,
- pj_sockaddr_get_str_addr(&event->src.rdata->addr),
- pj_sockaddr_get_port(&event->src.rdata->addr)));
- }
-
- /* Set the dlg in the transaction (dlg can be NULL). */
- tsx->module_data[ua->mod_id] = dlg;
-
- } else {
- /* This CAN happen with event->src_type == PJSIP_EVENT_TX_MSG
- * if UAS is responding to a transaction which does not exist.
- * Just ignore.
- */
- return;
- }
-
- /* Pass the event to the dlg. */
- if (dlg) {
- pjsip_dlg_on_tsx_event(dlg, tsx, event);
- }
-}
-
-/*
- * Register dialog to UA.
- */
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
- pj_str_t *key )
-{
- /* Assure that no entry with similar key exists in the hash table. */
- pj_assert( pj_hash_get( ua->dlg_table, key->ptr, key->slen) == 0);
-
- /* Insert entry to hash table. */
- pj_hash_set( dlg->pool, ua->dlg_table,
- key->ptr, key->slen, dlg);
-
- /* Insert to the list. */
- pj_list_insert_before(&ua->dlg_list, dlg);
- return PJ_SUCCESS;
-}
-
-/*
- * Create a new dialog.
- */
-PJ_DEF(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,
- pjsip_role_e role )
-{
- pj_pool_t *pool;
- pjsip_dlg *dlg;
-
- PJ_UNUSED_ARG(ua)
-
- /* Create pool for the dialog. */
- pool = pjsip_endpt_create_pool( ua->endpt, "pdlg%p",
- PJSIP_POOL_LEN_DIALOG,
- PJSIP_POOL_INC_DIALOG);
-
- /* Create the dialog. */
- dlg = pj_pool_calloc(pool, 1, sizeof(pjsip_dlg));
- dlg->pool = pool;
- dlg->ua = ua;
- dlg->role = role;
- sprintf(dlg->obj_name, "dlg%p", dlg);
-
- /* Create mutex for the dialog. */
- dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
- if (!dlg->mutex) {
- pjsip_endpt_destroy_pool(ua->endpt, pool);
- return NULL;
- }
-
- /* Create unique tag for the dialog. */
- pj_create_unique_string( pool, &dlg->local.tag );
-
- /* Register dialog. */
- pj_mutex_lock(ua->mutex);
- if (ua_register_dialog(ua, dlg, &dlg->local.tag) != PJ_SUCCESS) {
- pj_mutex_unlock(ua->mutex);
- pj_mutex_destroy(dlg->mutex);
- pjsip_endpt_destroy_pool( ua->endpt, pool );
- return NULL;
- }
- pj_mutex_unlock(ua->mutex);
-
- PJ_LOG(4, (dlg->obj_name, "new %s dialog created", pjsip_role_name(role)));
- return dlg;
-}
-
-/*
- * Destroy dialog.
- */
-PJ_DEF(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg )
-{
- PJ_LOG(5, (dlg->obj_name, "destroying.."));
-
- /* Lock dialog's mutex.
- * Check the mutex validity first since this function can be called
- * on dialog initialization failure (which might be because mutex could not
- * be allocated in the first place).
- */
- if (dlg->mutex) {
- pj_mutex_lock(dlg->mutex);
- }
-
- /* This must be called while holding dialog's mutex, if any. */
- pjsip_on_dialog_destroyed(dlg);
-
- /* Lock UA. */
- pj_mutex_lock(dlg->ua->mutex);
-
- /* Erase from hash table. */
- pj_hash_set( dlg->pool, dlg->ua->dlg_table,
- dlg->local.tag.ptr, dlg->local.tag.slen, NULL);
-
- /* Erase from the list. */
- pj_list_erase(dlg);
-
- /* Unlock UA. */
- pj_mutex_unlock(dlg->ua->mutex);
-
- /* Unlock mutex. */
- if (dlg->mutex) {
- pj_mutex_unlock(dlg->mutex);
- }
-
- /* Destroy the pool. */
- pjsip_endpt_destroy_pool( dlg->ua->endpt, dlg->pool);
-}
-
-/*
- * Dump user agent state to log file.
- */
-PJ_DEF(void) pjsip_ua_dump(pjsip_user_agent *ua)
-{
-#if PJ_LOG_MAX_LEVEL >= 3
- PJ_LOG(3,(LOG_THIS, "Dumping user agent"));
- PJ_LOG(3,(LOG_THIS, " Pool capacity=%u, used=%u",
- pj_pool_get_capacity(ua->pool),
- pj_pool_get_used_size(ua->pool)));
- PJ_LOG(3,(LOG_THIS, " Number of dialogs=%u", pj_hash_count(ua->dlg_table)));
-
- if (pj_hash_count(ua->dlg_table)) {
- pjsip_dlg *dlg;
-
- PJ_LOG(3,(LOG_THIS, " Dumping dialog list:"));
- dlg = ua->dlg_list.next;
- while (dlg != (pjsip_dlg*) &ua->dlg_list) {
- PJ_LOG(3, (LOG_THIS, " %s %s", dlg->obj_name,
- pjsip_dlg_state_str(dlg->state)));
- dlg = dlg->next;
- }
- }
-#endif
-}
-
diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
index 523b35a9..1caaa901 100644
--- a/pjsip/src/pjsip/sip_auth_client.c
+++ b/pjsip/src/pjsip/sip_auth_client.c
@@ -353,6 +353,42 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
}
+/* Clone session. */
+PJ_DEF(pj_status_t) pjsip_auth_clt_clone( pj_pool_t *pool,
+ pjsip_auth_clt_sess *sess,
+ const pjsip_auth_clt_sess *rhs )
+{
+ unsigned i;
+
+ PJ_ASSERT_RETURN(pool && sess && rhs, PJ_EINVAL);
+
+ sess->pool = pool;
+ sess->endpt = (pjsip_endpoint*)rhs->endpt;
+ sess->cred_cnt = rhs->cred_cnt;
+ sess->cred_info = pj_pool_alloc(pool,
+ sess->cred_cnt*sizeof(pjsip_cred_info));
+ for (i=0; i<rhs->cred_cnt; ++i) {
+ pj_strdup(pool, &sess->cred_info[i].realm, &rhs->cred_info[i].realm);
+ pj_strdup(pool, &sess->cred_info[i].scheme, &rhs->cred_info[i].scheme);
+ pj_strdup(pool, &sess->cred_info[i].username,
+ &rhs->cred_info[i].username);
+ sess->cred_info[i].data_type = rhs->cred_info[i].data_type;
+ pj_strdup(pool, &sess->cred_info[i].data, &rhs->cred_info[i].data);
+ }
+
+ /* TODO note:
+ * Cloning the full authentication client is quite a big task.
+ * We do only the necessary bits here, i.e. cloning the credentials.
+ * The drawback of this basic approach is, a forked dialog will have to
+ * re-authenticate itself on the next request because it has lost the
+ * cached authentication headers.
+ */
+ PJ_TODO(FULL_CLONE_OF_AUTH_CLIENT_SESSION);
+
+ return PJ_SUCCESS;
+}
+
+
/* Set client credentials. */
PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
int cred_cnt,
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
new file mode 100644
index 00000000..d387b8ae
--- /dev/null
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -0,0 +1,1138 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_util.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/guid.h>
+#include <pj/rand.h>
+#include <pj/array.h>
+#include <pj/except.h>
+#include <pj/hash.h>
+#include <pj/log.h>
+
+#define THIS_FILE "sip_dialog.c"
+
+
+PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m)
+{
+ pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 10}};
+ pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}};
+
+ return m->id == PJSIP_INVITE_METHOD ||
+ (pjsip_method_cmp(m, &subscribe)==0) ||
+ (pjsip_method_cmp(m, &refer)==0);
+}
+
+static pj_status_t create_dialog( pjsip_user_agent *ua,
+ pjsip_dialog **p_dlg)
+{
+ pjsip_endpoint *endpt;
+ pj_pool_t *pool;
+ pjsip_dialog *dlg;
+ pj_status_t status;
+
+ endpt = pjsip_ua_get_endpt(ua);
+ if (!endpt)
+ return PJ_EINVALIDOP;
+
+ pool = pjsip_endpt_create_pool(endpt, "dlg%p",
+ PJSIP_POOL_LEN_DIALOG,
+ PJSIP_POOL_INC_DIALOG);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ dlg = pj_pool_zalloc(pool, sizeof(pjsip_dialog));
+ PJ_ASSERT_RETURN(dlg != NULL, PJ_ENOMEM);
+
+ dlg->pool = pool;
+ pj_sprintf(dlg->obj_name, "dlg%p", dlg);
+ dlg->ua = ua;
+
+ status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ *p_dlg = dlg;
+ return PJ_SUCCESS;
+
+on_error:
+ if (dlg->mutex)
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(endpt, pool);
+ return status;
+}
+
+static void destroy_dialog( pjsip_dialog *dlg )
+{
+ if (dlg->mutex)
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+}
+
+
+/*
+ * Create an UAC dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
+ const pj_str_t *local_uri,
+ const pj_str_t *local_contact,
+ const pj_str_t *remote_uri,
+ const pj_str_t *target,
+ pjsip_dialog **p_dlg)
+{
+ pj_status_t status;
+ pj_str_t tmp;
+ pjsip_dialog *dlg;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(ua && local_uri && remote_uri && p_dlg, PJ_EINVAL);
+
+ /* Create dialog instance. */
+ status = create_dialog(ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Parse target. */
+ pj_strdup_with_null(dlg->pool, &tmp, target ? target : remote_uri);
+ dlg->target = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->target) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Init local info. */
+ dlg->local.info = pjsip_from_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, local_uri);
+ dlg->local.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->local.info->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Generate local tag. */
+ pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+ /* Calculate hash value of local tag. */
+ dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen);
+
+ /* Randomize local CSeq. */
+ dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+ dlg->local.cseq = dlg->local.cseq;
+
+ /* Init local contact. */
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp,
+ local_contact ? local_contact : local_uri);
+ dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+ PJSIP_PARSE_URI_AS_NAMEADDR);
+ if (!dlg->local.contact->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Init remote info. */
+ dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, remote_uri);
+ dlg->remote.info->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen, 0);
+ if (!dlg->remote.info->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ /* Initialize remote's CSeq to -1. */
+ dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+ /* Initial role is UAC. */
+ dlg->role = PJSIP_ROLE_UAC;
+
+ /* Secure? */
+ dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+ /* Generate Call-ID header. */
+ dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
+ pj_create_unique_string(dlg->pool, &dlg->call_id->id);
+
+ /* Initial route set is empty. */
+ pj_list_init(&dlg->route_set);
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua),
+ dlg->pool, 0);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg( ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Done! */
+ *p_dlg = dlg;
+
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Create UAS dialog.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_uas( pjsip_user_agent *ua,
+ pjsip_rx_data *rdata,
+ const pj_str_t *contact,
+ pjsip_dialog **p_dlg)
+{
+ pj_status_t status;
+ pjsip_hdr *contact_hdr;
+ pjsip_rr_hdr *rr;
+ pjsip_dialog *dlg;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(ua && rdata && p_dlg, PJ_EINVAL);
+
+ /* rdata must have request message. */
+ PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
+ PJSIP_ENOTREQUESTMSG);
+
+ /* Request must not have To tag.
+ * This should have been checked in the user agent (or application?).
+ */
+ PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen == 0, PJ_EINVALIDOP);
+
+ /* The request must be a dialog establishing request. */
+ PJ_ASSERT_RETURN(
+ pjsip_method_creates_dialog(&rdata->msg_info.msg->line.req.method),
+ PJ_EINVALIDOP);
+
+ /* Create dialog instance. */
+ status = create_dialog(ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Init local info from the To header. */
+ dlg->local.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.to);
+ pjsip_fromto_hdr_set_from(dlg->local.info);
+
+ /* Generate local tag. */
+ pj_create_unique_string(dlg->pool, &dlg->local.info->tag);
+
+ /* Calculate hash value of local tag. */
+ dlg->local.tag_hval = pj_hash_calc(0, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen);
+
+ /* Randomize local cseq */
+ dlg->local.first_cseq = pj_rand() % 0x7FFFFFFFL;
+ dlg->local.cseq = dlg->local.first_cseq;
+
+ /* Init local contact. */
+ /* TODO:
+ * Section 12.1.1, paragraph about using SIPS URI in Contact.
+ * If the request that initiated the dialog contained a SIPS URI
+ * in the Request-URI or in the top Record-Route header field value,
+ * if there was any, or the Contact header field if there was no
+ * Record-Route header field, the Contact header field in the response
+ * MUST be a SIPS URI.
+ */
+ if (contact) {
+ pj_str_t tmp;
+
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ pj_strdup_with_null(dlg->pool, &tmp, contact);
+ dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
+ PJSIP_PARSE_URI_AS_NAMEADDR);
+ if (!dlg->local.contact->uri) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+
+ } else {
+ dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
+ dlg->local.contact->uri = dlg->local.info->uri;
+ }
+
+ /* Init remote info from the From header. */
+ dlg->remote.info = pjsip_hdr_clone(dlg->pool, rdata->msg_info.from);
+ pjsip_fromto_hdr_set_to(dlg->remote.info);
+
+ /* Init remote's contact from Contact header. */
+ contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
+ NULL);
+ if (!contact_hdr) {
+ status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
+ goto on_error;
+ }
+ dlg->remote.contact = pjsip_hdr_clone(dlg->pool, contact_hdr);
+
+ /* Init remote's CSeq from CSeq header */
+ dlg->remote.cseq = dlg->remote.first_cseq = rdata->msg_info.cseq->cseq;
+
+ /* Set initial target to remote's Contact. */
+ dlg->target = dlg->remote.contact->uri;
+
+ /* Initial role is UAS */
+ dlg->role = PJSIP_ROLE_UAS;
+
+ /* Secure?
+ * RFC 3261 Section 12.1.1:
+ * If the request arrived over TLS, and the Request-URI contained a
+ * SIPS URI, the 'secure' flag is set to TRUE.
+ */
+ dlg->secure = PJSIP_TRANSPORT_IS_SECURE(rdata->tp_info.transport) &&
+ PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri);
+
+ /* Call-ID */
+ dlg->call_id = pjsip_hdr_clone(dlg->pool, rdata->msg_info.cid);
+
+ /* Route set.
+ * RFC 3261 Section 12.1.1:
+ * The route set MUST be set to the list of URIs in the Record-Route
+ * header field from the request, taken in order and preserving all URI
+ * parameters. If no Record-Route header field is present in the request,
+ * the route set MUST be set to the empty set.
+ */
+ pj_list_init(&dlg->route_set);
+ rr = rdata->msg_info.record_route;
+ while (rr != NULL) {
+ pjsip_route_hdr *route;
+
+ /* Clone the Record-Route, change the type to Route header. */
+ route = pjsip_hdr_clone(dlg->pool, rr);
+ pjsip_routing_hdr_set_route(route);
+
+ /* Add to route set. */
+ pj_list_push_back(&dlg->route_set, route);
+
+ /* Find next Record-Route header. */
+ rr = rr->next;
+ if (rr == (pjsip_rr_hdr*)&rdata->msg_info.msg->hdr)
+ break;
+ rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, rr);
+ }
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_init(&dlg->auth_sess, pjsip_ua_get_endpt(ua),
+ dlg->pool, 0);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Calculate hash value of remote tag. */
+ dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr,
+ dlg->remote.info->tag.slen);
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg( ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Put this dialog in rdata's mod_data */
+ rdata->endpt_info.mod_data[ua->id] = dlg;
+
+ PJ_TODO(DIALOG_APP_TIMER);
+
+ /* Done. */
+ *p_dlg = dlg;
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Create forked dialog from a response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
+ const pjsip_rx_data *rdata,
+ pjsip_dialog **new_dlg )
+{
+ pjsip_dialog *dlg;
+ const pjsip_route_hdr *r;
+ pj_status_t status;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(first_dlg && rdata && new_dlg, PJ_EINVAL);
+
+ /* rdata must be response message. */
+ PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+
+ /* To tag must present in the response. */
+ PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);
+
+ /* Create the dialog. */
+ status = create_dialog((pjsip_user_agent*)first_dlg->ua, &dlg);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Clone remote target. */
+ dlg->target = pjsip_uri_clone(dlg->pool, first_dlg->target);
+
+ /* Clone local info. */
+ dlg->local.info = pjsip_hdr_clone(dlg->pool, first_dlg->local.info);
+
+ /* Clone local tag. */
+ pj_strdup(dlg->pool, &dlg->local.info->tag, &first_dlg->local.info->tag);
+ dlg->local.tag_hval = first_dlg->local.tag_hval;
+
+ /* Clone local CSeq. */
+ dlg->local.first_cseq = first_dlg->local.first_cseq;
+ dlg->local.cseq = first_dlg->local.cseq;
+
+ /* Clone local Contact. */
+ dlg->local.contact = pjsip_hdr_clone(dlg->pool, first_dlg->local.contact);
+
+ /* Clone remote info. */
+ dlg->remote.info = pjsip_hdr_clone(dlg->pool, first_dlg->remote.info);
+
+ /* Set remote tag from the response. */
+ pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+
+ /* Initialize remote's CSeq to -1. */
+ dlg->remote.cseq = dlg->remote.first_cseq = -1;
+
+ /* Initial role is UAC. */
+ dlg->role = PJSIP_ROLE_UAC;
+
+ /* Secure? */
+ dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);
+
+ /* Clone Call-ID header. */
+ dlg->call_id = pjsip_hdr_clone(dlg->pool, first_dlg->call_id);
+
+ /* Duplicate Route-Set. */
+ pj_list_init(&dlg->route_set);
+ r = first_dlg->route_set.next;
+ while (r != &first_dlg->route_set) {
+ pjsip_route_hdr *h;
+
+ h = pjsip_hdr_clone(dlg->pool, r);
+ pj_list_push_back(&dlg->route_set, h);
+
+ r = r->next;
+ }
+
+ /* Init client authentication session. */
+ status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,
+ &first_dlg->auth_sess);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register this dialog to user agent. */
+ status = pjsip_ua_register_dlg(dlg->ua, dlg );
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Done! */
+ *new_dlg = dlg;
+
+ return PJ_SUCCESS;
+
+on_error:
+ destroy_dialog(dlg);
+ return status;
+}
+
+
+/*
+ * Destroy dialog.
+ */
+static pj_status_t unregister_and_destroy_dialog( pjsip_dialog *dlg )
+{
+ pj_status_t status;
+
+ /* Lock must have been held. */
+
+ /* Check dialog state. */
+ /* Number of sessions must be zero. */
+ PJ_ASSERT_RETURN(dlg->sess_count==0, PJ_EINVALIDOP);
+
+ /* MUST not have pending transactions. */
+ PJ_ASSERT_RETURN(dlg->tsx_count==0, PJ_EINVALIDOP);
+
+ /* Unregister from user agent. */
+ status = pjsip_ua_unregister_dlg(dlg->ua, dlg);
+ if (status != PJ_SUCCESS) {
+ pj_assert(!"Unexpected failed unregistration!");
+ return status;
+ }
+
+ /* Destroy this dialog. */
+ pj_mutex_destroy(dlg->mutex);
+ pjsip_endpt_release_pool(pjsip_ua_get_endpt(dlg->ua), dlg->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Set route_set
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dialog *dlg,
+ const pjsip_route_hdr *route_set )
+{
+ pjsip_route_hdr *r;
+
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+
+ /* Clear route set. */
+ pj_list_init(&dlg->route_set);
+
+ if (!route_set) {
+ pj_mutex_unlock(dlg->mutex);
+ return PJ_SUCCESS;
+ }
+
+ r = route_set->next;
+ while (r != route_set) {
+ pjsip_route_hdr *new_r;
+
+ new_r = pjsip_hdr_clone(dlg->pool, r);
+ pj_list_push_back(&dlg->route_set, new_r);
+
+ r = r->next;
+ }
+
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Increment session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg )
+{
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+ ++dlg->sess_count;
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Decrement session counter.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg )
+{
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
+
+ pj_mutex_lock(dlg->mutex);
+
+ --dlg->sess_count;
+
+ if (dlg->sess_count==0 && dlg->tsx_count==0)
+ status = unregister_and_destroy_dialog(dlg);
+ else {
+ pj_mutex_unlock(dlg->mutex);
+ status = PJ_SUCCESS;
+ }
+
+ return status;
+}
+
+
+/*
+ * Add usage.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_add_usage( pjsip_dialog *dlg,
+ pjsip_module *mod,
+ void *mod_data )
+{
+ unsigned index;
+
+ PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
+ PJ_ASSERT_RETURN(mod->id >= 0 && mod->id < PJSIP_MAX_MODULE,
+ PJ_EINVAL);
+ PJ_ASSERT_RETURN(dlg->usage_cnt < PJSIP_MAX_MODULE, PJ_EBUG);
+
+ pj_mutex_lock(dlg->mutex);
+
+ /* Usages are sorted on priority, lowest number first.
+ * Find position to put the new module, also makes sure that
+ * this module has not been registered before.
+ */
+ for (index=0; index<dlg->usage_cnt; ++index) {
+ if (dlg->usage[index] == mod) {
+ pj_assert(!"This module is already registered");
+ pj_mutex_unlock(dlg->mutex);
+ return PJSIP_ETYPEEXISTS;
+ }
+
+ if (dlg->usage[index]->priority > mod->priority)
+ break;
+ }
+
+ /* index holds position to put the module.
+ * Insert module at this index.
+ */
+ pj_array_insert(dlg->usage, sizeof(dlg->usage[0]), dlg->usage_cnt,
+ index, &mod);
+
+ /* Set module data. */
+ dlg->mod_data[mod->id] = mod_data;
+
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Create a new request within dialog (i.e. after the dialog session has been
+ * established). The construction of such requests follows the rule in
+ * RFC3261 section 12.2.1.
+ */
+static pj_status_t dlg_create_request_throw( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **p_tdata )
+{
+ pjsip_tx_data *tdata;
+ pjsip_contact_hdr *contact;
+ pjsip_route_hdr *route, *end_list;
+ pj_status_t status;
+
+ /* Contact Header field.
+ * Contact can only be present in requests that establish dialog (in the
+ * core SIP spec, only INVITE).
+ */
+ if (pjsip_method_creates_dialog(method))
+ contact = dlg->local.contact;
+ else
+ contact = NULL;
+
+ /*
+ * Create the request by cloning from the headers in the
+ * dialog.
+ */
+ status = pjsip_endpt_create_request_from_hdr(pjsip_ua_get_endpt(dlg->ua),
+ method,
+ dlg->target,
+ dlg->local.info,
+ dlg->remote.info,
+ contact,
+ dlg->call_id,
+ cseq,
+ NULL,
+ &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Just copy dialog route-set to Route header.
+ * The transaction will do the processing as specified in Section 12.2.1
+ * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
+ */
+ route = dlg->route_set.next;
+ end_list = &dlg->route_set;
+ for (; route != end_list; route = route->next ) {
+ pjsip_route_hdr *r;
+ r = pjsip_hdr_shallow_clone( tdata->pool, route );
+ pjsip_routing_hdr_set_route(r);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
+ }
+
+ /* Copy authorization headers. */
+ status = pjsip_auth_clt_init_req( &dlg->auth_sess, tdata );
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Done. */
+ *p_tdata = tdata;
+
+ return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Create outgoing request.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_request( pjsip_dialog *dlg,
+ const pjsip_method *method,
+ int cseq,
+ pjsip_tx_data **p_tdata)
+{
+ pj_status_t status;
+ pjsip_tx_data *tdata = NULL;
+ PJ_USE_EXCEPTION;
+
+ PJ_ASSERT_RETURN(dlg && method && p_tdata, PJ_EINVAL);
+
+ /* Lock dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Use outgoing CSeq and increment it by one. */
+ if (cseq <= 0)
+ cseq = dlg->local.cseq + 1;
+
+ /* Keep compiler happy */
+ status = PJ_EBUG;
+
+ /* Create the request. */
+ PJ_TRY {
+ status = dlg_create_request_throw(dlg, method, cseq, &tdata);
+ }
+ PJ_CATCH_ANY {
+ status = PJ_ENOMEM;
+ }
+ PJ_END;
+
+ /* Failed! Delete transmit data. */
+ if (status != PJ_SUCCESS && tdata) {
+ pjsip_tx_data_dec_ref( tdata );
+ tdata = NULL;
+ }
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ *p_tdata = tdata;
+
+ return status;
+}
+
+
+/*
+ * Update CSeq in outgoing request to reflect the dialog.
+ * Then increment local CSeq.
+ */
+static void update_cseq( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata )
+{
+ pjsip_msg *msg = tdata->msg;
+
+ /* Start locking the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Update dialog's CSeq and message's CSeq if request is not
+ * ACK nor CANCEL.
+ */
+ if (msg->line.req.method.id != PJSIP_CANCEL_METHOD &&
+ msg->line.req.method.id != PJSIP_ACK_METHOD)
+ {
+ pjsip_cseq_hdr *ch;
+
+ ch = PJSIP_MSG_CSEQ_HDR(msg);
+ PJ_ASSERT_ON_FAIL(ch!=NULL, return);
+
+ ch->cseq = dlg->local.cseq++;
+
+ /* Force the whole message to be re-printed. */
+ pjsip_tx_data_invalidate_msg( tdata );
+ }
+
+}
+
+/*
+ * Send request statefully, and update dialog'c CSeq.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ pjsip_transaction **p_tsx )
+{
+ pjsip_transaction *tsx;
+ pj_status_t status;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
+ PJSIP_ENOTREQUESTMSG);
+
+ /* Update CSeq */
+ update_cseq(dlg, tdata);
+
+ /* Create a new transaction.
+ * The transaction user is the user agent module.
+ */
+ status = pjsip_tsx_create_uac(dlg->ua, tdata, &tsx);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Attach this dialog to the transaction, so that user agent
+ * will dispatch events to this dialog.
+ */
+ tsx->mod_data[dlg->ua->id] = dlg;
+
+ /* Increment transaction counter. */
+ ++dlg->tsx_count;
+
+ /* Send the message. */
+ status = pjsip_tsx_send_msg(tsx, tdata);
+ if (status != PJ_SUCCESS) {
+ pjsip_tsx_terminate(tsx, tsx->status_code);
+ goto on_error;
+ }
+
+ /* Done. */
+ *p_tsx = tsx;
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ return PJ_SUCCESS;
+
+on_error:
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ /* Whatever happen delete the message. */
+ pjsip_tx_data_dec_ref( tdata );
+
+ *p_tsx = NULL;
+ return status;
+}
+
+
+/*
+ * Create response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_create_response( pjsip_dialog *dlg,
+ pjsip_rx_data *rdata,
+ int st_code,
+ const pj_str_t *st_text,
+ pjsip_tx_data **p_tdata)
+{
+ pj_status_t status;
+ pjsip_cseq_hdr *cseq;
+ pjsip_tx_data *tdata;
+ int st_class;
+
+ /* Create generic response. */
+ status = pjsip_endpt_create_response(pjsip_ua_get_endpt(dlg->ua),
+ rdata, st_code, st_text, &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Special treatment for 2xx response to request that establishes
+ * dialog.
+ *
+ * RFC 3261 Section 12.1.1
+ *
+ * When a UAS responds to a request with a response that establishes
+ * a dialog (such as a 2xx to INVITE):
+ * - MUST copy all Record-Route header field values from the request
+ * into the response (including the URIs, URI parameters, and any
+ * Record-Route header field parameters, whether they are known or
+ * unknown to the UAS) and MUST maintain the order of those values.
+ * - The Contact header field contains an address where the UAS would
+ * like to be contacted for subsequent requests in the dialog.
+ *
+ * Also from Table 3, page 119.
+ */
+ cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
+ pj_assert(cseq != NULL);
+
+ st_class = st_code / 100;
+
+ if (cseq->cseq == dlg->remote.first_cseq &&
+ (st_class==1 || st_class==2) && st_code != 100)
+ {
+ pjsip_hdr *rr, *hdr;
+
+ /* Duplicate Record-Route header from the request. */
+ rr = (pjsip_hdr*) rdata->msg_info.record_route;
+ while (rr) {
+ hdr = pjsip_hdr_clone(tdata->pool, rr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+
+ rr = rr->next;
+ if (rr == &rdata->msg_info.msg->hdr)
+ break;
+ rr = pjsip_msg_find_hdr(rdata->msg_info.msg,
+ PJSIP_H_RECORD_ROUTE, rr);
+ }
+ }
+
+ /* Contact header. */
+ if (pjsip_method_creates_dialog(&cseq->method)) {
+ /* Add Contact header for 1xx, 2xx, 3xx and 485 response. */
+ if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
+ st_code==485)
+ {
+ /* Add contact header. */
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+
+ /* Add Allow header in 2xx and 405 response. */
+ if (st_class==2 || st_code==405) {
+ const pjsip_hdr *c_hdr;
+ c_hdr = pjsip_endpt_get_capability(pjsip_ua_get_endpt(dlg->ua),
+ PJSIP_H_ALLOW, NULL);
+ if (c_hdr) {
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+ }
+
+ /* Add Supported header in 2xx response. */
+ if (st_class==2) {
+ const pjsip_hdr *c_hdr;
+ c_hdr = pjsip_endpt_get_capability(pjsip_ua_get_endpt(dlg->ua),
+ PJSIP_H_SUPPORTED, NULL);
+ if (c_hdr) {
+ pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr);
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ }
+ }
+
+ }
+
+ /* Add To tag in all responses except 100 */
+ if (st_code != 100 && rdata->msg_info.to->tag.slen == 0) {
+ pjsip_to_hdr *to;
+
+ to = PJSIP_MSG_TO_HDR(tdata->msg);
+ pj_assert(to != NULL);
+
+ to->tag = dlg->local.info->tag;
+ }
+
+ /* Unlock the dialog. */
+ pj_mutex_unlock(dlg->mutex);
+
+ /* Done. */
+ *p_tdata = tdata;
+ return PJ_SUCCESS;
+}
+
+/*
+ * Modify response.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_modify_response( pjsip_dialog *dlg,
+ pjsip_tx_data *tdata,
+ int st_code,
+ const pj_str_t *st_text)
+{
+
+ PJ_ASSERT_RETURN(dlg && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+ PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
+
+ tdata->msg->line.status.code = st_code;
+ if (st_text) {
+ pj_strdup(tdata->pool, &tdata->msg->line.status.reason, st_text);
+ } else {
+ tdata->msg->line.status.reason = *pjsip_get_status_text(st_code);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Send response statefully.
+ */
+PJ_DEF(pj_status_t) pjsip_dlg_send_response( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_tx_data *tdata)
+{
+ /* Sanity check. */
+ PJ_ASSERT_RETURN(dlg && tsx && tdata && tdata->msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
+ PJSIP_ENOTRESPONSEMSG);
+
+ /* The transaction must belong to this dialog. */
+ PJ_ASSERT_RETURN(tsx->mod_data[dlg->ua->id] == dlg, PJ_EINVALIDOP);
+
+ /* Check that transaction method and cseq match the response.
+ * This operation is sloooww (search CSeq header twice), that's why
+ * we only do it in debug mode.
+ */
+#if defined(PJ_DEBUG) && PJ_DEBUG!=0
+ PJ_ASSERT_RETURN( PJSIP_MSG_CSEQ_HDR(tdata->msg)->cseq == tsx->cseq &&
+ pjsip_method_cmp(&PJSIP_MSG_CSEQ_HDR(tdata->msg)->method,
+ &tsx->method)==0,
+ PJ_EINVALIDOP);
+#endif
+
+ return pjsip_tsx_send_msg(tsx, tdata);
+}
+
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+ pj_status_t status;
+ pjsip_transaction *tsx;
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Create UAS transaction for this request. */
+ status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
+ PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;});
+
+ /* Put this dialog in the transaction data. */
+ tsx->mod_data[dlg->ua->id] = dlg;
+
+ /* Add transaction count. */
+ ++dlg->tsx_count;
+
+ /* Report the request to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+ pj_bool_t processed;
+
+ if (!dlg->usage[i]->on_rx_request)
+ continue;
+
+ processed = (*dlg->usage[i]->on_rx_request)(rdata);
+
+ if (processed)
+ break;
+ }
+
+ if (i==dlg->usage_cnt) {
+ pjsip_tx_data *tdata;
+
+ PJ_LOG(4,(dlg->obj_name,
+ "%s is unhandled by dialog usages. "
+ "Dialog will response with 500 (Internal Server Error)",
+ pjsip_rx_data_get_info(rdata)));
+ status = pjsip_endpt_create_response(pjsip_ua_get_endpt(dlg->ua),
+ rdata,
+ PJSIP_SC_INTERNAL_SERVER_ERROR,
+ NULL, &tdata);
+ if (status == PJ_SUCCESS)
+ status = pjsip_tsx_send_msg(tsx, tdata);
+
+ if (status != PJ_SUCCESS) {
+ char errmsg[PJSIP_ERR_MSG_SIZE];
+ pj_strerror(status, errmsg, sizeof(errmsg));
+ PJ_LOG(4,(dlg->obj_name,"Error sending %s: %s",
+ pjsip_tx_data_get_info(tdata), errmsg));
+ pjsip_tsx_terminate(tsx, 500);
+ }
+ }
+
+on_return:
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving incoming response
+ * message.
+ */
+void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
+{
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ /* Update the remote tag, if none is specified yet. */
+ if (dlg->remote.info->tag.slen == 0 && rdata->msg_info.to->tag.slen != 0) {
+
+ pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
+
+ /* No need to update remote's tag_hval since its never used. */
+ }
+
+ /* Check that rdata already has dialog in mod_data. */
+ pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);
+
+ /* Pass to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+ pj_bool_t processed;
+
+ if (!dlg->usage[i]->on_rx_response)
+ continue;
+
+ processed = (*dlg->usage[i]->on_rx_response)(rdata);
+
+ if (processed)
+ break;
+ }
+
+ if (i==dlg->usage_cnt) {
+ PJ_LOG(4,(dlg->obj_name, "%s is unhandled by dialog usages",
+ pjsip_rx_data_get_info(rdata)));
+ }
+
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+}
+
+/* This function is called by user agent upon receiving transaction
+ * state notification.
+ */
+void pjsip_dlg_on_tsx_state( pjsip_dialog *dlg,
+ pjsip_transaction *tsx,
+ pjsip_event *e )
+{
+ unsigned i;
+
+ /* Lock the dialog. */
+ pj_mutex_lock(dlg->mutex);
+
+ if (tsx->state == PJSIP_TSX_STATE_TERMINATED)
+ --dlg->tsx_count;
+
+ /* Pass to dialog usages. */
+ for (i=0; i<dlg->usage_cnt; ++i) {
+
+ if (!dlg->usage[i]->on_tsx_state)
+ continue;
+
+ (*dlg->usage[i]->on_tsx_state)(tsx, e);
+ }
+
+ if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 &&
+ dlg->sess_count == 0)
+ {
+ /* Time to destroy dialog. */
+ unregister_and_destroy_dialog(dlg);
+
+ } else {
+ /* Unlock dialog. */
+ pj_mutex_unlock(dlg->mutex);
+ }
+}
+
+
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 71e7cff8..3d109e4c 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -77,18 +77,12 @@ struct pjsip_endpoint
/** Module list, sorted by priority. */
pjsip_module module_list;
- /** Number of supported methods. */
- unsigned method_cnt;
-
- /** Array of supported methods. */
- const pjsip_method *methods[MAX_METHODS];
-
- /** Allow header. */
- pjsip_allow_hdr *allow_hdr;
-
/** Route header list. */
pjsip_route_hdr route_hdr_list;
+ /** Capability header list. */
+ pjsip_hdr cap_hdr;
+
/** Additional request headers. */
pjsip_hdr req_hdr;
};
@@ -196,7 +190,6 @@ PJ_DEF(pj_status_t) pjsip_endpt_register_module( pjsip_endpoint *endpt,
pj_list_insert_before(m, mod);
/* Done. */
- PJ_TODO(BUILD_ALLOW_HEADER_BASED_ON_MODULES_SUPPORTED_METHODS);
on_return:
pj_rwmutex_unlock_write(endpt->mod_mutex);
@@ -248,19 +241,86 @@ PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
/* Done. */
status = PJ_SUCCESS;
- PJ_TODO(REMOVE_METHODS_FROM_ALLOW_HEADER_WHEN_MODULE_IS_UNREGISTERED);
-
on_return:
pj_rwmutex_unlock_write(endpt->mod_mutex);
return status;
}
+
+/*
+ * Get the value of the specified capability header field.
+ */
+PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_capability( pjsip_endpoint *endpt,
+ int htype,
+ const pj_str_t *hname)
+{
+ pjsip_hdr *hdr = endpt->cap_hdr.next;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(endpt != NULL, NULL);
+ PJ_ASSERT_RETURN(htype != PJSIP_H_OTHER || hname, NULL);
+
+ if (htype != PJSIP_H_OTHER) {
+ while (hdr != &endpt->cap_hdr) {
+ if (hdr->type == htype)
+ return hdr;
+ hdr = hdr->next;
+ }
+ }
+ return NULL;
+}
+
+
/*
- * Get "Allow" header.
+ * Add or register new capabilities as indicated by the tags to the
+ * appropriate header fields in the endpoint.
*/
-PJ_DEF(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
+PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
+ pjsip_module *mod,
+ int htype,
+ const pj_str_t *hname,
+ unsigned count,
+ const pj_str_t tags[])
{
- return endpt->allow_hdr;
+ pjsip_generic_array_hdr *hdr;
+ unsigned i;
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(endpt!=NULL && mod!=NULL && count>0 && tags, PJ_EINVAL);
+ PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT ||
+ htype==PJSIP_H_ALLOW ||
+ htype==PJSIP_H_SUPPORTED,
+ PJ_EINVAL);
+
+ /* Find the header. */
+ hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt,
+ htype, hname);
+
+ /* Create the header when it's not present */
+ if (hdr == NULL) {
+ switch (htype) {
+ case PJSIP_H_ACCEPT:
+ hdr = pjsip_accept_hdr_create(endpt->pool);
+ break;
+ case PJSIP_H_ALLOW:
+ hdr = pjsip_allow_hdr_create(endpt->pool);
+ break;
+ case PJSIP_H_SUPPORTED:
+ hdr = pjsip_supported_hdr_create(endpt->pool);
+ break;
+ default:
+ return PJ_EINVAL;
+ }
+ }
+
+ /* Add the tags to the header. */
+ for (i=0; i<count; ++i) {
+ pj_strdup(endpt->pool, &hdr->values[hdr->count], &tags[i]);
+ ++hdr->count;
+ }
+
+ /* Done. */
+ return PJ_SUCCESS;
}
/*
@@ -325,7 +385,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
pj_status_t status;
pj_pool_t *pool;
pjsip_endpoint *endpt;
- pjsip_max_forwards_hdr *mf_hdr;
+ pjsip_max_fwd_hdr *mf_hdr;
pj_lock_t *lock = NULL;
PJ_LOG(5, (THIS_FILE, "Creating endpoint instance..."));
@@ -419,10 +479,13 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
pj_list_init(&endpt->route_hdr_list);
/* Add "Max-Forwards" for request header. */
- mf_hdr = pjsip_max_forwards_hdr_create(endpt->pool);
- mf_hdr->ivalue = PJSIP_MAX_FORWARDS_VALUE;
+ mf_hdr = pjsip_max_fwd_hdr_create(endpt->pool,
+ PJSIP_MAX_FORWARDS_VALUE);
pj_list_insert_before( &endpt->req_hdr, mf_hdr);
+ /* Initialize capability header list. */
+ pj_list_init(&endpt->cap_hdr);
+
/* Done. */
*p_endpt = endpt;
return status;
diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c
index a2faf1a2..077f6553 100644
--- a/pjsip/src/pjsip/sip_errno.c
+++ b/pjsip/src/pjsip/sip_errno.c
@@ -45,6 +45,7 @@ static const struct
{ PJSIP_EINVALIDSTATUS, "Invalid status code"},
+ { PJSIP_EINVALIDURI, "Invalid URI" },
{ PJSIP_EINVALIDSCHEME, "Invalid URI scheme" },
{ PJSIP_EMISSINGREQURI, "Missing Request-URI" },
{ PJSIP_EINVALIDREQURI, "Invalid Request URI" },
@@ -77,7 +78,10 @@ static const struct
{ PJSIP_EAUTHACCNOTFOUND, "Account or credential not found" },
{ PJSIP_EAUTHACCDISABLED, "Account or credential is disabled" },
{ PJSIP_EAUTHINVALIDREALM, "Invalid authorization realm"},
- { PJSIP_EAUTHINVALIDDIGEST, "Invalid authorization digest" }
+ { PJSIP_EAUTHINVALIDDIGEST, "Invalid authorization digest" },
+
+ /* UA/dialog layer. */
+ { PJSIP_EMISSINGTAG, "Missing From/To tag parameter" }
};
diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index 6010ba05..23e97f77 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -498,31 +498,40 @@ static pjsip_hdr_vptr generic_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_string_hdr_print,
};
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
- const pj_str_t *hnames )
+PJ_DEF(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames,
+ const pj_str_t *hvalue)
{
- pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+ pjsip_generic_string_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
hdr->sname = hdr->name;
}
- hdr->hvalue.ptr = NULL;
- hdr->hvalue.slen = 0;
+ if (hvalue) {
+ pj_strdup(pool, &hdr->hvalue, hvalue);
+ } else {
+ hdr->hvalue.ptr = NULL;
+ hdr->hvalue.slen = 0;
+ }
+
return hdr;
}
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
- const pj_str_t *hname,
- const pj_str_t *hvalue)
+PJ_DEF(pjsip_generic_string_hdr*)
+pjsip_generic_string_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames,
+ const pj_str_t *hvalue)
{
- pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, hname);
- pj_strdup(pool, &hdr->hvalue, hvalue);
- return hdr;
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
+ return pjsip_generic_string_hdr_init(pool, mem, hnames, hvalue);
}
-static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
- char *buf, pj_size_t size)
+static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
+ char *buf, pj_size_t size)
{
char *p = buf;
@@ -543,11 +552,12 @@ static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr,
static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool,
const pjsip_generic_string_hdr *rhs)
{
- pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, &rhs->name);
+ pjsip_generic_string_hdr *hdr;
+
+ hdr = pjsip_generic_string_hdr_create(pool, &rhs->name, &rhs->hvalue);
hdr->type = rhs->type;
hdr->sname = hdr->name;
- pj_strdup( pool, &hdr->hvalue, &rhs->hvalue);
return hdr;
}
@@ -578,26 +588,28 @@ static pjsip_hdr_vptr generic_int_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_int_hdr_print,
};
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
- const pj_str_t *hnames )
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames,
+ int value)
{
- pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+ pjsip_generic_int_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_int_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
hdr->sname = hdr->name;
}
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
- const pj_str_t *hname,
- int value)
+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames,
+ int value)
{
- pjsip_generic_int_hdr *hdr = pjsip_generic_int_hdr_create(pool, hname);
- hdr->ivalue = value;
- return hdr;
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
+ return pjsip_generic_int_hdr_init(pool, mem, hnames, value);
}
static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr,
@@ -651,10 +663,13 @@ static pjsip_hdr_vptr generic_array_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_generic_array_hdr_print,
};
-PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
- const pj_str_t *hnames)
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_init( pj_pool_t *pool,
+ void *mem,
+ const pj_str_t *hnames)
{
- pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+ pjsip_generic_array_hdr *hdr = mem;
+
init_hdr(hdr, PJSIP_H_OTHER, &generic_array_hdr_vptr);
if (hnames) {
pj_strdup(pool, &hdr->name, hnames);
@@ -662,6 +677,13 @@ PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
}
hdr->count = 0;
return hdr;
+}
+
+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_hdr_create( pj_pool_t *pool,
+ const pj_str_t *hnames)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
+ return pjsip_generic_array_hdr_init(pool, mem, hnames);
}
@@ -713,38 +735,69 @@ static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t
/*
* Accept header.
*/
-PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_accept_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_accept_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ACCEPT, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_accept_hdr));
+ return pjsip_accept_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Allow header.
*/
-PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_allow_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_allow_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ALLOW, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_allow_hdr));
+ return pjsip_allow_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Call-ID header.
*/
-PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_cid_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_cid_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);
return hdr;
+
+}
+
+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_cid_hdr));
+ return pjsip_cid_hdr_init(pool, mem);
}
@@ -763,14 +816,24 @@ static pjsip_hdr_vptr clen_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_clen_hdr_print,
};
-PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_clen_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+ pjsip_clen_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CONTENT_LENGTH, &clen_hdr_vptr);
hdr->len = 0;
return hdr;
}
+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
+ return pjsip_clen_hdr_init(pool, mem);
+}
+
static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr,
char *buf, pj_size_t size)
{
@@ -815,9 +878,13 @@ static pjsip_hdr_vptr cseq_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_cseq_hdr_print,
};
-PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+ pjsip_cseq_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_CSEQ, &cseq_hdr_vptr);
hdr->cseq = 0;
hdr->method.id = PJSIP_OTHER_METHOD;
@@ -826,6 +893,12 @@ PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
return hdr;
}
+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
+ return pjsip_cseq_hdr_init(pool, mem);
+}
+
static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size)
{
char *p = buf;
@@ -884,15 +957,26 @@ static pjsip_hdr_vptr contact_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_contact_hdr_print,
};
-PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_contact_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_contact_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_contact_hdr));
init_hdr(hdr, PJSIP_H_CONTACT, &contact_hdr_vptr);
hdr->expires = -1;
pj_list_init(&hdr->other_param);
return hdr;
}
+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_contact_hdr));
+ return pjsip_contact_hdr_init(pool, mem);
+}
+
static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf,
pj_size_t size)
{
@@ -1002,11 +1086,23 @@ static pjsip_hdr_vptr ctype_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_ctype_hdr_print,
};
-PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_ctype_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_ctype_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_ctype_hdr));
init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
return hdr;
+
+}
+
+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_ctype_hdr));
+ return pjsip_ctype_hdr_init(pool, mem);
}
static int print_media_type(char *buf, const pjsip_media_type *media)
@@ -1066,12 +1162,25 @@ static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool,
/*
* Expires header.
*/
-PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value)
{
- pjsip_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_expires_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_EXPIRES, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
+
+}
+
+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_expires_hdr));
+ return pjsip_expires_hdr_init(pool, mem, value);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1093,30 +1202,53 @@ static pjsip_hdr_vptr fromto_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_fromto_hdr_print,
};
-PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_from_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_from_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_from_hdr));
init_hdr(hdr, PJSIP_H_FROM, &fromto_hdr_vptr);
pj_list_init(&hdr->other_param);
return hdr;
}
-PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
{
- pjsip_to_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_from_hdr));
+ return pjsip_from_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_init( pj_pool_t *pool,
+ void *mem )
+{
+ pjsip_to_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_to_hdr));
init_hdr(hdr, PJSIP_H_TO, &fromto_hdr_vptr);
pj_list_init(&hdr->other_param);
return hdr;
+
+}
+
+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_to_hdr));
+ return pjsip_to_hdr_init(pool, mem);
}
-PJ_DEF(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr )
+PJ_DEF(pjsip_from_hdr*) pjsip_fromto_hdr_set_from( pjsip_fromto_hdr *hdr )
{
hdr->type = PJSIP_H_FROM;
hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_FROM];
return hdr;
}
-PJ_DEF(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr )
+PJ_DEF(pjsip_to_hdr*) pjsip_fromto_hdr_set_to( pjsip_fromto_hdr *hdr )
{
hdr->type = PJSIP_H_TO;
hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_TO];
@@ -1183,12 +1315,25 @@ pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,
/*
* Max-Forwards header.
*/
-PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value)
{
- pjsip_max_forwards_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_max_fwd_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_MAX_FORWARDS, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
+
+}
+
+PJ_DEF(pjsip_max_fwd_hdr*) pjsip_max_fwd_hdr_create(pj_pool_t *pool,
+ int value)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_max_fwd_hdr));
+ return pjsip_max_fwd_hdr_init(pool, mem, value);
}
@@ -1196,14 +1341,26 @@ PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
/*
* Min-Expires header.
*/
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value )
{
- pjsip_min_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_min_expires_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_MIN_EXPIRES, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
+PJ_DEF(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_min_expires_hdr));
+ return pjsip_min_expires_hdr_init(pool, mem, value );
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Record-Route and Route header.
@@ -1219,24 +1376,45 @@ static pjsip_hdr_vptr routing_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_routing_hdr_print,
};
-PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_rr_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_rr_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_RECORD_ROUTE, &routing_hdr_vptr);
pjsip_name_addr_init(&hdr->name_addr);
pj_list_init(&hdr->other_param);
return hdr;
+
}
-PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
{
- pjsip_route_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_rr_hdr));
+ return pjsip_rr_hdr_init(pool, mem);
+}
+
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_init( pj_pool_t *pool,
+ void *mem )
+{
+ pjsip_route_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_ROUTE, &routing_hdr_vptr);
pjsip_name_addr_init(&hdr->name_addr);
pj_list_init(&hdr->other_param);
return hdr;
}
+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_route_hdr));
+ return pjsip_route_hdr_init(pool, mem);
+}
+
PJ_DEF(pjsip_rr_hdr*) pjsip_routing_hdr_set_rr( pjsip_routing_hdr *hdr )
{
hdr->type = PJSIP_H_RECORD_ROUTE;
@@ -1304,52 +1482,93 @@ static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool,
/*
* Require header.
*/
-PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_require_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_require_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_REQUIRE, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_require_hdr));
+ return pjsip_require_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Retry-After header.
*/
-PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_init( pj_pool_t *pool,
+ void *mem,
+ int value )
{
- pjsip_retry_after_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_retry_after_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_RETRY_AFTER, &generic_int_hdr_vptr);
- hdr->ivalue = 0;
+ hdr->ivalue = value;
return hdr;
}
+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool,
+ int value )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_retry_after_hdr));
+ return pjsip_retry_after_hdr_init(pool, mem, value );
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Supported header.
*/
-PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_supported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_supported_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
init_hdr(hdr, PJSIP_H_SUPPORTED, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_supported_hdr));
+ return pjsip_supported_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Unsupported header.
*/
-PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_unsupported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
+ pjsip_unsupported_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
init_hdr(hdr, PJSIP_H_UNSUPPORTED, &generic_array_hdr_vptr);
hdr->count = 0;
return hdr;
}
+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_unsupported_hdr));
+ return pjsip_unsupported_hdr_init(pool, mem);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Via header.
@@ -1365,15 +1584,26 @@ static pjsip_hdr_vptr via_hdr_vptr =
(pjsip_hdr_print_fptr) &pjsip_via_hdr_print,
};
-PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_init( pj_pool_t *pool,
+ void *mem )
{
- pjsip_via_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
+ pjsip_via_hdr *hdr = mem;
+
+ PJ_UNUSED_ARG(pool);
+
+ pj_memset(mem, 0, sizeof(pjsip_via_hdr));
init_hdr(hdr, PJSIP_H_VIA, &via_hdr_vptr);
- //hdr->sent_by.port = 5060;
hdr->ttl_param = -1;
hdr->rport_param = -1;
pj_list_init(&hdr->other_param);
return hdr;
+
+}
+
+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
+{
+ void *mem = pj_pool_alloc(pool, sizeof(pjsip_via_hdr));
+ return pjsip_via_hdr_init(pool, mem);
}
static int pjsip_via_hdr_print( pjsip_via_hdr *hdr,
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index f281824b..352ea2ed 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -1167,10 +1167,10 @@ static pjsip_sip_uri *int_parse_sip_url( pj_scanner *scanner,
}
if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
} else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
- url = pjsip_url_create(pool, 1);
+ url = pjsip_sip_uri_create(pool, 1);
} else {
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
@@ -1541,7 +1541,7 @@ static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
/* Parse Expires header. */
static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx)
{
- pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool);
+ pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1601,7 +1601,7 @@ static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )
static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)
{
pjsip_retry_after_hdr *hdr;
- hdr = pjsip_retry_after_hdr_create(ctx->pool);
+ hdr = pjsip_retry_after_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1673,8 +1673,8 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
/* Parse Max-Forwards header. */
static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
{
- pjsip_max_forwards_hdr *hdr;
- hdr = pjsip_max_forwards_hdr_create(ctx->pool);
+ pjsip_max_fwd_hdr *hdr;
+ hdr = pjsip_max_fwd_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
if (ctx->rdata)
@@ -1687,7 +1687,7 @@ static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
static pjsip_hdr* parse_hdr_min_expires(pjsip_parse_ctx *ctx)
{
pjsip_min_expires_hdr *hdr;
- hdr = pjsip_min_expires_hdr_create(ctx->pool);
+ hdr = pjsip_min_expires_hdr_create(ctx->pool, 0);
parse_generic_int_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
}
@@ -1820,7 +1820,7 @@ static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx )
{
pjsip_generic_string_hdr *hdr;
- hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL);
+ hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL, NULL);
parse_generic_string_hdr(hdr, ctx->scanner);
return (pjsip_hdr*)hdr;
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
index 4563f6dc..73e50dfa 100644
--- a/pjsip/src/pjsip/sip_tel_uri.c
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -64,9 +64,9 @@ static pj_str_t pjsip_PH_CTX_STR = { "phone-context", 13 };
static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri* );
static void *tel_uri_get_uri( pjsip_tel_uri* );
-static int tel_uri_print( pjsip_uri_context_e context,
- const pjsip_tel_uri *url,
- char *buf, pj_size_t size);
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *url,
+ char *buf, pj_size_t size);
static int tel_uri_cmp( pjsip_uri_context_e context,
const pjsip_tel_uri *url1, const pjsip_tel_uri *url2);
static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs);
@@ -164,9 +164,9 @@ pj_status_t pjsip_tel_uri_subsys_init(void)
}
/* Print tel: URI */
-static int tel_uri_print( pjsip_uri_context_e context,
- const pjsip_tel_uri *uri,
- char *buf, pj_size_t size)
+static pj_ssize_t tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *uri,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 61632ed7..39bc8d20 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -61,8 +61,6 @@ static struct mod_tsx_layer
-1, /* Module ID */
PJSIP_MOD_PRIORITY_TSX_LAYER, /* Priority. */
NULL, /* User_data. */
- 0, /* Methods count. */
- { NULL }, /* Array of methods. */
mod_tsx_layer_load, /* load(). */
mod_tsx_layer_start, /* start() */
mod_tsx_layer_stop, /* stop() */
@@ -507,16 +505,19 @@ static pj_status_t mod_tsx_layer_register_tsx( pjsip_transaction *tsx)
pj_mutex_lock(mod_tsx_layer.mutex);
/* Check if no transaction with the same key exists. */
- if (pj_hash_get( mod_tsx_layer.htable, &tsx->transaction_key.ptr,
- tsx->transaction_key.slen) != NULL)
- {
- pj_mutex_unlock(mod_tsx_layer.mutex);
- return PJ_EEXISTS;
- }
+ PJ_ASSERT_ON_FAIL(pj_hash_get( mod_tsx_layer.htable,
+ &tsx->transaction_key.ptr,
+ tsx->transaction_key.slen,
+ &tsx->hashed_key) == NULL,
+ {
+ pj_mutex_unlock(mod_tsx_layer.mutex);
+ return PJ_EEXISTS;
+ }
+ );
/* Register the transaction to the hash table. */
pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, tsx);
+ tsx->transaction_key.slen, tsx->hashed_key, tsx);
/* Unlock mutex. */
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -538,7 +539,7 @@ static void mod_tsx_layer_unregister_tsx( pjsip_transaction *tsx)
/* Register the transaction to the hash table. */
pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr,
- tsx->transaction_key.slen, NULL);
+ tsx->transaction_key.slen, tsx->hashed_key, NULL);
/* Unlock mutex. */
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -554,7 +555,7 @@ PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
pjsip_transaction *tsx;
pj_mutex_lock(mod_tsx_layer.mutex);
- tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen, NULL );
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -648,7 +649,7 @@ static pj_bool_t mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata)
/* Find transaction. */
pj_mutex_lock( mod_tsx_layer.mutex );
- tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
/* Transaction not found.
@@ -689,7 +690,7 @@ static pj_bool_t mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata)
/* Find transaction. */
pj_mutex_lock( mod_tsx_layer.mutex );
- tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen );
+ tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, NULL );
if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
/* Transaction not found.
@@ -1035,6 +1036,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uac( pjsip_module *tsx_user,
PJSIP_ROLE_UAC, &tsx->method,
&via->branch_param);
+ /* Calculate hashed key value. */
+ tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen);
+
PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
tsx->transaction_key.ptr));
@@ -1140,6 +1145,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
return status;
}
+ /* Calculate hashed key value. */
+ tsx->hashed_key = pj_hash_calc(0, tsx->transaction_key.ptr,
+ tsx->transaction_key.slen);
+
/* Duplicate branch parameter for transaction. */
branch = &rdata->msg_info.via->branch_param;
pj_strdup(tsx->pool, &tsx->branch, branch);
@@ -1179,6 +1188,9 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user,
return status;
}
+ /* Put this transaction in rdata's mod_data. */
+ rdata->endpt_info.mod_data[mod_tsx_layer.mod.id] = tsx;
+
/* Unlock transaction and return. */
unlock_tsx(tsx, &lck);
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 46d98d99..88531876 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -43,22 +43,20 @@ static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata);
*/
static pjsip_module mod_msg_print =
{
- NULL, NULL, /* prev and next */
- { "mod-msg-print", 13}, /* Name. */
- -1, /* Id */
- PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
- NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
- NULL, /* load() */
- NULL, /* start() */
- NULL, /* stop() */
- NULL, /* unload() */
- NULL, /* on_rx_request() */
- NULL, /* on_rx_response() */
- &mod_on_tx_msg, /* on_tx_request() */
- &mod_on_tx_msg, /* on_tx_response() */
- NULL, /* on_tsx_state() */
+ NULL, NULL, /* prev and next */
+ { "mod-msg-print", 13}, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */
+ NULL, /* User data. */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ NULL, /* on_rx_request() */
+ NULL, /* on_rx_response() */
+ &mod_on_tx_msg, /* on_tx_request() */
+ &mod_on_tx_msg, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
};
/*
@@ -348,7 +346,7 @@ PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata )
{
if (tdata==NULL || tdata->msg==NULL)
- return "INVALID MSG";
+ return "NULL";
if (tdata->info)
return tdata->info;
@@ -589,7 +587,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
*/
key_len = sizeof(tp->key.type) + tp->addr_len;
pj_lock_acquire(mgr->lock);
- pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, tp);
+ pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, tp);
pj_lock_release(mgr->lock);
return PJ_SUCCESS;
@@ -617,7 +615,7 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
* Unregister from hash table.
*/
key_len = sizeof(tp->key.type) + tp->addr_len;
- pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, NULL);
+ pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, 0, NULL);
pj_lock_release(mgr->lock);
@@ -878,7 +876,8 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
}
/* Perform basic header checking. */
- if (rdata->msg_info.cid->id.ptr == NULL ||
+ if (rdata->msg_info.cid == NULL ||
+ rdata->msg_info.cid->id.slen == 0 ||
rdata->msg_info.from == NULL ||
rdata->msg_info.to == NULL ||
rdata->msg_info.via == NULL ||
@@ -961,7 +960,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
key.type = type;
pj_memcpy(&key.addr, remote, addr_len);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
if (transport == NULL) {
unsigned flag = pjsip_transport_get_flag_from_type(type);
const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
@@ -974,7 +973,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pj_memset(addr, 0, sizeof(pj_sockaddr_in));
key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
}
/* For datagram INET transports, try lookup with zero address.
*/
@@ -987,7 +986,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
addr->sin_family = PJ_AF_INET;
key_len = sizeof(key.type) + sizeof(pj_sockaddr_in);
- transport = pj_hash_get(mgr->table, &key, key_len);
+ transport = pj_hash_get(mgr->table, &key, key_len, NULL);
}
}
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
new file mode 100644
index 00000000..90885847
--- /dev/null
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -0,0 +1,674 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip/sip_ua_layer.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_dialog.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_transaction.h>
+#include <pj/os.h>
+#include <pj/hash.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+
+
+#define THIS_FILE "sip_ua_layer.c"
+
+/*
+ * Static prototypes.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt);
+static pj_status_t mod_ua_unload(void);
+static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata);
+static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata);
+static void mod_ua_on_tsx_state(pjsip_transaction*, pjsip_event*);
+
+
+extern long pjsip_dlg_lock_tls_id; /* defined in sip_dialog.c */
+
+/* This struct is used to represent list of dialog inside a dialog set.
+ * We don't want to use pjsip_dialog for this purpose, to save some
+ * memory (about 100 bytes per dialog set).
+ */
+struct dlg_set_head
+{
+ PJ_DECL_LIST_MEMBER(pjsip_dialog);
+};
+
+/* This struct represents a dialog set.
+ * This is the value that will be put in the UA's hash table.
+ */
+struct dlg_set
+{
+ /* To put this node in free dlg_set nodes in UA. */
+ PJ_DECL_LIST_MEMBER(struct dlg_set);
+
+ /* This is the buffer to store this entry in the hash table. */
+ char ht_entry[PJ_HASH_ENTRY_SIZE];
+
+ /* List of dialog in this dialog set. */
+ struct dlg_set_head dlg_list;
+};
+
+
+/*
+ * Module interface.
+ */
+static struct user_agent
+{
+ pjsip_module mod;
+ pj_pool_t *pool;
+ pjsip_endpoint *endpt;
+ pj_mutex_t *mutex;
+ pj_hash_table_t *dlg_table;
+ pjsip_ua_init_param param;
+ struct dlg_set free_dlgset_nodes;
+
+} mod_ua =
+{
+ {
+ NULL, NULL, /* prev, next. */
+ { "mod-ua", 6 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
+ NULL, /* User data. */
+ &mod_ua_load, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ &mod_ua_unload, /* unload() */
+ &mod_ua_on_rx_request, /* on_rx_request() */
+ &mod_ua_on_rx_response, /* on_rx_response() */
+ NULL, /* on_tx_request. */
+ NULL, /* on_tx_response() */
+ &mod_ua_on_tsx_state, /* on_tsx_state() */
+ }
+};
+
+/*
+ * mod_ua_load()
+ *
+ * Called when module is being loaded by endpoint.
+ */
+static pj_status_t mod_ua_load(pjsip_endpoint *endpt)
+{
+ pj_status_t status;
+
+ /* Initialize the user agent. */
+ mod_ua.endpt = endpt;
+ mod_ua.pool = pjsip_endpt_create_pool( endpt, "ua%p", PJSIP_POOL_LEN_UA,
+ PJSIP_POOL_INC_UA);
+ if (mod_ua.pool == NULL)
+ return PJ_ENOMEM;
+
+ status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT);
+ if (mod_ua.dlg_table == NULL)
+ return PJ_ENOMEM;
+
+ pj_list_init(&mod_ua.free_dlgset_nodes);
+
+ /* Initialize dialog lock. */
+ status = pj_thread_local_alloc(&pjsip_dlg_lock_tls_id);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
+
+ return PJ_SUCCESS;
+
+}
+
+/*
+ * mod_ua_unload()
+ *
+ * Called when module is being unloaded.
+ */
+static pj_status_t mod_ua_unload(void)
+{
+ pj_thread_local_free(pjsip_dlg_lock_tls_id);
+ pj_mutex_destroy(mod_ua.mutex);
+
+ /* Release pool */
+ if (mod_ua.pool) {
+ pjsip_endpt_release_pool( mod_ua.endpt, mod_ua.pool );
+ }
+ return PJ_SUCCESS;
+}
+
+/*
+ * mod_ua_on_tsx_stats()
+ *
+ * Called on changed on transaction state.
+ */
+static void mod_ua_on_tsx_state( pjsip_transaction *tsx, pjsip_event *e)
+{
+ pjsip_dialog *dlg;
+
+ /* Get the dialog where this transaction belongs. */
+ dlg = tsx->mod_data[mod_ua.mod.id];
+
+ /* Must have the dialog instance! */
+ PJ_ASSERT_ON_FAIL(dlg != NULL, return);
+
+ /* Hand over the event to the dialog. */
+ pjsip_dlg_on_tsx_state(dlg, tsx, e);
+}
+
+
+/*
+ * Init user agent module and register it to the endpoint.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_init( pjsip_endpoint *endpt,
+ const pjsip_ua_init_param *prm)
+{
+ pj_status_t status;
+
+ /* Check if module already registered. */
+ PJ_ASSERT_RETURN(mod_ua.mod.id == -1, PJ_EINVALIDOP);
+
+ /* Copy param, if exists. */
+ if (prm)
+ pj_memcpy(&mod_ua.param, prm, sizeof(pjsip_ua_init_param));
+
+ /* Register the module. */
+ status = pjsip_endpt_register_module(endpt, &mod_ua.mod);
+
+ return status;
+}
+
+/*
+ * Get the instance of the user agent.
+ *
+ */
+PJ_DEF(pjsip_user_agent*) pjsip_ua_instance(void)
+{
+ return &mod_ua.mod;
+}
+
+
+/*
+ * Destroy the user agent layer.
+ */
+PJ_DEF(pj_status_t) pjsip_ua_destroy(void)
+{
+ /* Check if module already destroyed. */
+ PJ_ASSERT_RETURN(mod_ua.mod.id != -1, PJ_EINVALIDOP);
+
+ return pjsip_endpt_unregister_module(mod_ua.endpt, &mod_ua.mod);
+}
+
+
+
+/*
+ * Create key to identify dialog set.
+ */
+PJ_DEF(void) pjsip_ua_create_dlg_set_key( pj_pool_t *pool,
+ pj_str_t *set_key,
+ const pj_str_t *call_id,
+ const pj_str_t *local_tag)
+{
+ PJ_ASSERT_ON_FAIL(pool && set_key && call_id && local_tag, return;);
+
+ set_key->slen = call_id->slen + local_tag->slen + 1;
+ set_key->ptr = pj_pool_alloc(pool, set_key->slen);
+ pj_assert(set_key->ptr != NULL);
+
+ pj_memcpy(set_key->ptr, call_id->ptr, call_id->slen);
+ set_key->ptr[call_id->slen] = '$';
+ pj_memcpy(set_key->ptr + call_id->slen + 1,
+ local_tag->ptr, local_tag->slen);
+}
+
+/*
+ * Acquire one dlg_set node to be put in the hash table.
+ * This will first look in the free nodes list, then allocate
+ * a new one from UA's pool when one is not available.
+ */
+static struct dlg_set *alloc_dlgset_node(void)
+{
+ struct dlg_set *set;
+
+ if (!pj_list_empty(&mod_ua.free_dlgset_nodes)) {
+ set = mod_ua.free_dlgset_nodes.next;
+ pj_list_erase(set);
+ return set;
+ } else {
+ set = pj_pool_alloc(mod_ua.pool, sizeof(struct dlg_set));
+ return set;
+ }
+}
+
+/*
+ * Register new dialog. Called by pjsip_dlg_create_uac() and
+ * pjsip_dlg_create_uas();
+ */
+PJ_DEF(pj_status_t) pjsip_ua_register_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg )
+{
+ /* Sanity check. */
+ PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+ /* For all dialogs, local tag (inc hash) must has been initialized. */
+ PJ_ASSERT_RETURN(dlg->local.info && dlg->local.info->tag.slen &&
+ dlg->local.tag_hval != 0, PJ_EBUG);
+
+ /* For UAS dialog, remote tag (inc hash) must have been initialized. */
+ PJ_ASSERT_RETURN(dlg->role==PJSIP_ROLE_UAC ||
+ (dlg->role==PJSIP_ROLE_UAS && dlg->remote.info->tag.slen
+ && dlg->remote.tag_hval != 0), PJ_EBUG);
+
+ /* Lock the user agent. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* For UAC, check if there is existing dialog in the same set. */
+ if (dlg->role == PJSIP_ROLE_UAC) {
+ struct dlg_set *dlg_set;
+
+ dlg_set = pj_hash_get( mod_ua.dlg_table, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen,
+ &dlg->local.tag_hval);
+
+ if (dlg_set) {
+ /* This is NOT the first dialog in the dialog set.
+ * Just add this dialog in the list.
+ */
+ pj_assert(dlg_set->dlg_list.next != (void*)&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ } else {
+ /* This is the first dialog in the dialog set.
+ * Create the dialog set and add this dialog to it.
+ */
+ dlg_set = alloc_dlgset_node();
+ pj_list_init(&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ /* Register the dialog set in the hash table. */
+ pj_hash_set_np(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ }
+
+ } else {
+ /* For UAS, create the dialog set with a single dialog as member. */
+ struct dlg_set *dlg_set;
+
+ dlg_set = alloc_dlgset_node();
+ pj_list_init(&dlg_set->dlg_list);
+ pj_list_push_back(&dlg_set->dlg_list, dlg);
+
+ dlg->dlg_set = dlg_set;
+
+ pj_hash_set_np(mod_ua.dlg_table,
+ dlg->local.info->tag.ptr, dlg->local.info->tag.slen,
+ dlg->local.tag_hval, dlg_set->ht_entry, dlg_set);
+ }
+
+ /* Unlock user agent. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Done. */
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_ua_unregister_dlg( pjsip_user_agent *ua,
+ pjsip_dialog *dlg )
+{
+ struct dlg_set *dlg_set;
+ pjsip_dialog *d;
+
+ /* Sanity-check arguments. */
+ PJ_ASSERT_RETURN(ua && dlg, PJ_EINVAL);
+
+ /* Check that dialog has been registered. */
+ PJ_ASSERT_RETURN(dlg->dlg_set, PJ_EINVALIDOP);
+
+ /* Lock user agent. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Find this dialog from the dialog set. */
+ dlg_set = dlg->dlg_set;
+ d = dlg_set->dlg_list.next;
+ while (d != (pjsip_dialog*)&dlg_set->dlg_list && d != dlg) {
+ d = d->next;
+ }
+
+ if (d != dlg) {
+ pj_assert(!"Dialog is not registered!");
+ pj_mutex_unlock(mod_ua.mutex);
+ return PJ_EINVALIDOP;
+ }
+
+ /* Remove this dialog from the list. */
+ pj_list_erase(dlg);
+
+ /* If dialog list is empty, remove the dialog set from the hash table. */
+ if (pj_list_empty(&dlg_set->dlg_list)) {
+ pj_hash_set(NULL, mod_ua.dlg_table, dlg->local.info->tag.ptr,
+ dlg->local.info->tag.slen, dlg->local.tag_hval, NULL);
+
+ /* Return dlg_set to free nodes. */
+ pj_list_push_back(&mod_ua.free_dlgset_nodes, dlg_set);
+ }
+
+ /* Unlock user agent. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Done. */
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pjsip_dialog*) pjsip_rdata_get_dlg( pjsip_rx_data *rdata )
+{
+ return rdata->endpt_info.mod_data[mod_ua.mod.id];
+}
+
+PJ_DEF(pjsip_dialog*) pjsip_tsx_get_dlg( pjsip_transaction *tsx )
+{
+ return tsx->mod_data[mod_ua.mod.id];
+}
+
+
+/*
+ * Find the first dialog in dialog set in hash table for an incoming message.
+ */
+static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata )
+{
+ /* CANCEL message doesn't have To tag, so we must lookup the dialog
+ * by finding the INVITE UAS transaction being cancelled.
+ */
+ if (rdata->msg_info.cseq->method.id == PJSIP_CANCEL_METHOD) {
+
+ pjsip_dialog *dlg;
+
+ /* Create key for the rdata, but this time, use INVITE as the
+ * method.
+ */
+ pj_str_t key;
+ pjsip_role_e role;
+ pjsip_transaction *tsx;
+
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+ role = PJSIP_ROLE_UAS;
+ else
+ role = PJSIP_ROLE_UAC;
+
+ pjsip_tsx_create_key(rdata->tp_info.pool, &key, role,
+ &pjsip_invite_method, rdata);
+
+ /* Lookup the INVITE transaction */
+ tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+
+ /* We should find the dialog attached to the INVITE transaction */
+ if (tsx) {
+ dlg = tsx->mod_data[mod_ua.mod.id];
+ pj_mutex_unlock(tsx->mutex);
+
+ return dlg->dlg_set;
+
+ } else {
+ return NULL;
+ }
+
+
+ } else {
+ pj_str_t *tag;
+ struct dlg_set *dlg_set;
+
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
+ tag = &rdata->msg_info.to->tag;
+ else
+ tag = &rdata->msg_info.from->tag;
+
+ /* Lookup the dialog set. */
+ dlg_set = pj_hash_get(mod_ua.dlg_table, tag->ptr, tag->slen, NULL);
+ return dlg_set;
+ }
+}
+
+/* On received requests. */
+static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata)
+{
+ struct dlg_set *dlg_set;
+ pj_str_t *from_tag;
+ pjsip_dialog *dlg;
+
+ /* Lock user agent before looking up the dialog hash table. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Lookup the dialog set, based on the To tag header. */
+ dlg_set = find_dlg_set_for_msg(rdata);
+
+ /* Bail out if dialog is not found. */
+ if (dlg_set == NULL) {
+ /* Not ours. */
+ pj_mutex_unlock(mod_ua.mutex);
+ return PJ_FALSE;
+ }
+
+ /* Dialog set has been found.
+ * Find the dialog in the dialog set based on the content of the From tag.
+ */
+ from_tag = &rdata->msg_info.from->tag;
+ dlg = dlg_set->dlg_list.next;
+ while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+
+ if (pj_strcmp(&dlg->remote.info->tag, from_tag) == 0)
+ break;
+
+ dlg = dlg->next;
+ }
+
+ /* Dialog MUST be found! */
+ if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+ /* Not found. Mulfunction UAC? */
+ pj_mutex_unlock(mod_ua.mutex);
+ pjsip_endpt_respond_stateless(mod_ua.endpt, rdata,
+ PJSIP_SC_CALL_TSX_DOES_NOT_EXIST,
+ NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Mark the dialog id of the request. */
+ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+ /* Done processing in the UA */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ /* Pass to dialog. */
+ pjsip_dlg_on_rx_request(dlg, rdata);
+
+ /* Report as handled. */
+ return PJ_TRUE;
+}
+
+
+/* On rx response notification.
+ */
+static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata)
+{
+ pjsip_transaction *tsx;
+ struct dlg_set *dlg_set;
+ pjsip_dialog *dlg = NULL;
+
+ /*
+ * Find the dialog instance for the response.
+ * All outgoing dialog requests are sent statefully, which means
+ * there will be an UAC transaction associated with this response,
+ * and the dialog instance will be recorded in that transaction.
+ *
+ * But even when transaction is found, there is possibility that
+ * the response is a forked response.
+ */
+
+ /* Check if transaction is present. */
+ tsx = pjsip_rdata_get_tsx(rdata);
+ if (!tsx) {
+ /* Check if dialog is present in the transaction. */
+ dlg = pjsip_tsx_get_dlg(tsx);
+ if (!dlg)
+ return PJ_FALSE;
+
+ /* Get the dialog set. */
+ dlg_set = dlg->dlg_set;
+
+ /* Even if transaction is found and (candidate) dialog has been
+ * identified, it's possible that the request has forked.
+ */
+
+ } else {
+ /* Transaction is not present.
+ * Check if this is a 2xx/OK response to INVITE, which in this
+ * case the response will be handled directly by the
+ * dialog.
+ */
+ pjsip_cseq_hdr *cseq_hdr = rdata->msg_info.cseq;
+
+ if (cseq_hdr->method.id != PJSIP_INVITE_METHOD ||
+ rdata->msg_info.msg->line.status.code / 100 != 2)
+ {
+ /* Not a 2xx response to INVITE.
+ * This must be some stateless response sent by other modules,
+ * or a very late response.
+ */
+ return PJ_FALSE;
+ }
+
+ /* Lock user agent before accessing the hash table. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ /* Get the dialog set. */
+ dlg_set = pj_hash_get(mod_ua.dlg_table,
+ rdata->msg_info.from->tag.ptr,
+ rdata->msg_info.from->tag.slen,
+ NULL);
+
+ /* Done with accessing the hash table. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ if (!dlg_set) {
+ /* Strayed 2xx response!! */
+ PJ_LOG(4,(THIS_FILE,
+ "Received strayed 2xx response (no dialog is found)"
+ " from %s:%d: %s",
+ rdata->pkt_info.src_name, rdata->pkt_info.src_port,
+ pjsip_rx_data_get_info(rdata)));
+
+ return PJ_TRUE;
+ }
+ }
+
+ /* At this point, we must have the dialog set, and the dialog set
+ * must have a dialog in the list.
+ */
+ pj_assert(dlg_set && !pj_list_empty(&dlg_set->dlg_list));
+
+ /* Check for forked response.
+ * Request will fork only for the initial INVITE request.
+ */
+ if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
+ rdata->msg_info.cseq->cseq == dlg_set->dlg_list.next->local.first_cseq)
+ {
+ pj_str_t *to_tag = &rdata->msg_info.to->tag;
+
+ /* Must hold UA mutex before accessing dialog set. */
+ pj_mutex_lock(mod_ua.mutex);
+
+ dlg = dlg_set->dlg_list.next;
+ while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) {
+
+ /* If there is dialog with no remote tag (i.e. dialog has not
+ * been established yet), then send this response to that
+ * dialog.
+ */
+ if (dlg->remote.info->tag.slen == 0)
+ break;
+
+ /* Otherwise find the one with matching To tag. */
+ if (pj_strcmp(to_tag, &dlg->remote.info->tag) == 0)
+ break;
+
+ dlg = dlg->next;
+ }
+
+ /* If no dialog with matching remote tag is found, this must be
+ * a forked response.
+ */
+ if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) {
+ /* Report to application about forked condition.
+ * Application can either create a dialog or ignore the response.
+ */
+ if (mod_ua.param.on_dlg_forked)
+ dlg = (*mod_ua.param.on_dlg_forked)(dlg_set->dlg_list.next,
+ rdata);
+ else
+ dlg = NULL;
+
+ /* Ignore this response if application doesn't want to
+ * create a dialog.
+ */
+ if (dlg == NULL) {
+ pj_mutex_unlock(mod_ua.mutex);
+
+ PJ_LOG(4,(THIS_FILE,
+ "Unhandled forked %s from %s:%d",
+ pjsip_rx_data_get_info(rdata),
+ rdata->pkt_info.src_name, rdata->pkt_info.src_port));
+
+ return PJ_TRUE;
+ }
+ }
+
+ /* Done with the dialog set. */
+ pj_mutex_unlock(mod_ua.mutex);
+
+ } else {
+ /* Either this is a non-INVITE response, or subsequent INVITE
+ * within dialog. The dialog should have been identified when
+ * the transaction was found.
+ */
+ pj_assert(tsx != NULL);
+ pj_assert(dlg != NULL);
+ }
+
+ /* The dialog must have been found. */
+ pj_assert(dlg != NULL);
+
+ /* Put the dialog instance in the rdata. */
+ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
+
+ /* Pass the response to the dialog. */
+ pjsip_dlg_on_rx_response(dlg, rdata);
+
+ /* Done. */
+ return PJ_TRUE;
+}
+
+
diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c
index 17994051..c408d0d9 100644
--- a/pjsip/src/pjsip/sip_uri.c
+++ b/pjsip/src/pjsip/sip_uri.c
@@ -140,15 +140,15 @@ static pj_str_t sips_str = { "sips", 4 };
static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
const pjsip_name_addr *rhs);
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
- const pjsip_name_addr *name,
- char *buf, pj_size_t size);
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+ const pjsip_name_addr *name,
+ char *buf, pj_size_t size);
static int pjsip_name_addr_compare( pjsip_uri_context_e context,
const pjsip_name_addr *naddr1,
const pjsip_name_addr *naddr2);
-static int pjsip_url_print( pjsip_uri_context_e context,
- const pjsip_sip_uri *url,
- char *buf, pj_size_t size);
+static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
+ const pjsip_sip_uri *url,
+ char *buf, pj_size_t size);
static int pjsip_url_compare( pjsip_uri_context_e context,
const pjsip_sip_uri *url1,
const pjsip_sip_uri *url2);
@@ -204,7 +204,7 @@ static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
return name->uri;
}
-PJ_DEF(void) pjsip_url_init(pjsip_sip_uri *url, int secure)
+PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, int secure)
{
pj_memset(url, 0, sizeof(*url));
url->ttl_param = -1;
@@ -213,16 +213,16 @@ PJ_DEF(void) pjsip_url_init(pjsip_sip_uri *url, int secure)
pj_list_init(&url->header_param);
}
-PJ_DEF(pjsip_sip_uri*) pjsip_url_create( pj_pool_t *pool, int secure )
+PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool, int secure )
{
pjsip_sip_uri *url = pj_pool_alloc(pool, sizeof(pjsip_sip_uri));
- pjsip_url_init(url, secure);
+ pjsip_sip_uri_init(url, secure);
return url;
}
-static int pjsip_url_print( pjsip_uri_context_e context,
- const pjsip_sip_uri *url,
- char *buf, pj_size_t size)
+static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
+ const pjsip_sip_uri *url,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
@@ -465,8 +465,8 @@ static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
}
-PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_sip_uri *url,
- const pjsip_sip_uri *rhs)
+PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
+ const pjsip_sip_uri *rhs)
{
pj_strdup( pool, &url->user, &rhs->user);
pj_strdup( pool, &url->passwd, &rhs->passwd);
@@ -488,8 +488,8 @@ static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, const pjsip_sip_uri *rhs)
if (!url)
return NULL;
- pjsip_url_init(url, IS_SIPS(rhs));
- pjsip_url_assign(pool, url, rhs);
+ pjsip_sip_uri_init(url, IS_SIPS(rhs));
+ pjsip_sip_uri_assign(pool, url, rhs);
return url;
}
@@ -513,9 +513,9 @@ PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
return name_addr;
}
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
- const pjsip_name_addr *name,
- char *buf, pj_size_t size)
+static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
+ const pjsip_name_addr *name,
+ char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index f69ad9b3..af02e994 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -128,9 +128,9 @@ static void init_request_throw( pjsip_endpoint *endpt,
while (hparam != &uri->header_param) {
pjsip_generic_string_hdr *hdr;
- hdr = pjsip_generic_string_hdr_create_with_text(tdata->pool,
- &hparam->name,
- &hparam->value);
+ hdr = pjsip_generic_string_hdr_create(tdata->pool,
+ &hparam->name,
+ &hparam->value);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)hdr);
hparam = hparam->next;
}
@@ -302,9 +302,9 @@ pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
/* Duplicate target URI and headers. */
target = pjsip_uri_clone(tdata->pool, param_target);
from = pjsip_hdr_clone(tdata->pool, param_from);
- pjsip_fromto_set_from(from);
+ pjsip_fromto_hdr_set_from(from);
to = pjsip_hdr_clone(tdata->pool, param_to);
- pjsip_fromto_set_to(to);
+ pjsip_fromto_hdr_set_to(to);
if (param_contact)
contact = pjsip_hdr_clone(tdata->pool, param_contact);
else
diff --git a/pjsip/src/pjsip-ua/sip_ua_private.h b/pjsip/src/test-pjsip/dlg_core_test.c
index 8a174afe..348e3c3a 100644
--- a/pjsip/src/pjsip-ua/sip_ua_private.h
+++ b/pjsip/src/test-pjsip/dlg_core_test.c
@@ -16,21 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_UA_PRIVATE_H__
-#define __PJSIP_UA_PRIVATE_H__
-
-/*
- * Internal dialog functions.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg,
- pjsip_rx_data *rdata );
-
-
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg,
- pjsip_transaction *tsx,
- pjsip_event *event);
-
-
-#endif /* __PJSIP_UA_PRIVATE_H__ */
+#include "test.h"
+#include <pjsip.h>
diff --git a/pjsip/src/test-pjsip/msg_logger.c b/pjsip/src/test-pjsip/msg_logger.c
index faa36b53..45a4cbaf 100644
--- a/pjsip/src/test-pjsip/msg_logger.c
+++ b/pjsip/src/test-pjsip/msg_logger.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "msg_logger.c"
@@ -64,8 +64,6 @@ static pjsip_module mod_msg_logger =
-1, /* Id */
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c
index 8fe879a3..f5debe84 100644
--- a/pjsip/src/test-pjsip/msg_test.c
+++ b/pjsip/src/test-pjsip/msg_test.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define POOL_SIZE 8000
@@ -348,7 +348,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "INVITE sip:user@foo SIP/2.0\n" */
pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
msg->line.req.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "foo");
@@ -360,7 +360,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
fromto->uri = (pjsip_uri*)name_addr;
pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "joe.user");
pj_strdup2(pool, &url->host, "bar.otherdomain.com");
@@ -371,7 +371,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
fromto->uri = (pjsip_uri*)name_addr;
pj_strdup2(pool, &name_addr->display, "Fellow User");
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "foo.bar.domain.com");
@@ -399,7 +399,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
contact->expires = 3600;
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "joe");
pj_strdup2(pool, &url->host, "bar");
@@ -410,7 +410,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
contact->q1000 = 500;
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user");
pj_strdup2(pool, &url->host, "host");
@@ -420,7 +420,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->user, "user2");
pj_strdup2(pool, &url->host, "host2");
@@ -435,7 +435,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
routing = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
url->lr_param = 1;
@@ -443,7 +443,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* " <sip:server10.biloxi.com;lr>\r" */
routing = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "server10.biloxi.com");
url->lr_param = 1;
@@ -451,7 +451,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Record-Route: <sip:server10.biloxi.com>,\r\n" */
routing = pjsip_rr_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "server10.biloxi.com");
url->lr_param = 0;
@@ -459,7 +459,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* " <sip:bigbox3.site3.atlanta.com;lr>\n" */
routing = pjsip_rr_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
routing->name_addr.uri = (pjsip_uri*)url;
pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
url->lr_param = 1;
@@ -497,7 +497,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Organization: \r" */
str.ptr = "Organization";
str.slen = 12;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
generic->hvalue.ptr = NULL;
generic->hvalue.slen = 0;
@@ -505,7 +505,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "Max-Forwards: 70\n" */
str.ptr = "Max-Forwards";
str.slen = 12;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = "70";
str.slen = 2;
@@ -514,7 +514,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* "X-Header: \r\n" */
str.ptr = "X-Header";
str.slen = 8;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = NULL;
str.slen = 0;
@@ -523,7 +523,7 @@ static pjsip_msg *create_msg0(pj_pool_t *pool)
/* P-Associated-URI:\r\n */
str.ptr = "P-Associated-URI";
str.slen = 16;
- generic = pjsip_generic_string_hdr_create(pool, &str);
+ generic = pjsip_generic_string_hdr_create(pool, &str, NULL);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
str.ptr = NULL;
str.slen = 0;
@@ -538,7 +538,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
pjsip_route_hdr *route;
pjsip_name_addr *name_addr;
pjsip_sip_uri *url;
- pjsip_max_forwards_hdr *max_fwd;
+ pjsip_max_fwd_hdr *max_fwd;
pjsip_to_hdr *to;
pjsip_from_hdr *from;
pjsip_contact_hdr *contact;
@@ -581,22 +581,21 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
//"Route: <sip:proxy.sipprovider.com>\r\n"
route = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
route->name_addr.uri = (pjsip_uri*)url;
url->host = pj_str("proxy.sipprovider.com");
//"Route: <sip:proxy.supersip.com:5060>\r\n"
route = pjsip_route_hdr_create(pool);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)route);
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
route->name_addr.uri = (pjsip_uri*)url;
url->host = pj_str("proxy.supersip.com");
url->port = 5060;
//"Max-Forwards: 70\r\n"
- max_fwd = pjsip_max_forwards_hdr_create(pool);
+ max_fwd = pjsip_max_fwd_hdr_create(pool, 70);
pjsip_msg_add_hdr(msg, (pjsip_hdr*)max_fwd);
- max_fwd->ivalue = 70;
//"To: Bob <sip:bob@biloxi.com>;tag=a6c85cf\r\n"
to = pjsip_to_hdr_create(pool);
@@ -604,7 +603,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
name_addr->display = pj_str("Bob");
to->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("bob");
url->host = pj_str("biloxi.com");
@@ -616,7 +615,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
name_addr = pjsip_name_addr_create(pool);
name_addr->display = pj_str("Alice");
from->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_FALSE);
+ url = pjsip_sip_uri_create(pool, PJ_FALSE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("alice");
url->host = pj_str("atlanta.com");
@@ -638,7 +637,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool)
pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
name_addr = pjsip_name_addr_create(pool);
contact->uri = (pjsip_uri*)name_addr;
- url = pjsip_url_create(pool, PJ_TRUE);
+ url = pjsip_sip_uri_create(pool, PJ_TRUE);
name_addr->uri = (pjsip_uri*)url;
url->user = pj_str("bob");
url->host = pj_str("192.0.2.4");
diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c
index d634cc80..dd3453f8 100644
--- a/pjsip/src/test-pjsip/test.c
+++ b/pjsip/src/test-pjsip/test.c
@@ -20,7 +20,7 @@
#include "test.h"
#include <pjlib.h>
-#include <pjsip_core.h>
+#include <pjsip.h>
#define THIS_FILE "test.c"
diff --git a/pjsip/src/test-pjsip/transport_loop_test.c b/pjsip/src/test-pjsip/transport_loop_test.c
index f4e6bb3c..351fb7b6 100644
--- a/pjsip/src/test-pjsip/transport_loop_test.c
+++ b/pjsip/src/test-pjsip/transport_loop_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_loop_test.c"
diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c
index 74f6d796..df6f55eb 100644
--- a/pjsip/src/test-pjsip/transport_test.c
+++ b/pjsip/src/test-pjsip/transport_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_test.c"
@@ -101,8 +101,6 @@ static pjsip_module my_module =
-1, /* Id */
PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -305,8 +303,6 @@ static pjsip_module rt_module =
-1, /* Id */
PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c
index ebc0557d..cf5f0ca5 100644
--- a/pjsip/src/test-pjsip/transport_udp_test.c
+++ b/pjsip/src/test-pjsip/transport_udp_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "transport_udp_test.c"
diff --git a/pjsip/src/test-pjsip/tsx_basic_test.c b/pjsip/src/test-pjsip/tsx_basic_test.c
index 1db86f8d..6be0ea2a 100644
--- a/pjsip/src/test-pjsip/tsx_basic_test.c
+++ b/pjsip/src/test-pjsip/tsx_basic_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_basic_test.c"
diff --git a/pjsip/src/test-pjsip/tsx_uac_test.c b/pjsip/src/test-pjsip/tsx_uac_test.c
index 2ec94e5a..c699bc54 100644
--- a/pjsip/src/test-pjsip/tsx_uac_test.c
+++ b/pjsip/src/test-pjsip/tsx_uac_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_uac_test.c"
@@ -103,8 +103,6 @@ static pjsip_module tsx_user =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -124,8 +122,6 @@ static pjsip_module msg_receiver =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c
index ecc174c4..ed8f8574 100644
--- a/pjsip/src/test-pjsip/tsx_uas_test.c
+++ b/pjsip/src/test-pjsip/tsx_uas_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "tsx_uas_test.c"
@@ -142,8 +142,6 @@ static pjsip_module tsx_user =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
@@ -163,8 +161,6 @@ static pjsip_module msg_sender =
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
NULL, /* User data. */
- 0, /* Number of methods supported (=0). */
- { 0 }, /* Array of methods (none) */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c
index 327ea084..d39fad42 100644
--- a/pjsip/src/test-pjsip/txdata_test.c
+++ b/pjsip/src/test-pjsip/txdata_test.c
@@ -18,7 +18,7 @@
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL))
diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c
index 28bdedd9..a221f4ca 100644
--- a/pjsip/src/test-pjsip/uri_test.c
+++ b/pjsip/src/test-pjsip/uri_test.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "test.h"
-#include <pjsip_core.h>
+#include <pjsip.h>
#include <pjlib.h>
#define THIS_FILE "uri_test.c"
@@ -317,7 +317,7 @@ struct uri_test
static pjsip_uri *create_uri0(pj_pool_t *pool)
{
/* "sip:localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -326,7 +326,7 @@ static pjsip_uri *create_uri0(pj_pool_t *pool)
static pjsip_uri *create_uri1(pj_pool_t *pool)
{
/* "sip:user@localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2( pool, &url->user, "user");
pj_strdup2( pool, &url->host, "localhost");
@@ -337,7 +337,7 @@ static pjsip_uri *create_uri1(pj_pool_t *pool)
static pjsip_uri *create_uri2(pj_pool_t *pool)
{
/* "sip:user:password@localhost:5060" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2( pool, &url->user, "user");
pj_strdup2( pool, &url->passwd, "password");
@@ -350,7 +350,7 @@ static pjsip_uri *create_uri2(pj_pool_t *pool)
static pjsip_uri *create_uri3(pj_pool_t *pool)
{
/* Like: "sip:localhost:5060", but without the port. */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -359,7 +359,7 @@ static pjsip_uri *create_uri3(pj_pool_t *pool)
static pjsip_uri *create_uri4(pj_pool_t *pool)
{
/* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
pj_strdup2(pool, &url->transport_param, "tcp");
@@ -386,7 +386,7 @@ static pjsip_uri *create_uri5(pj_pool_t *pool)
/* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
"?Subject=Hello%20There&Server=SIP%20Server"
*/
- pjsip_sip_uri *url = pjsip_url_create(pool, 0);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
pj_strdup2(pool, &url->user_param, "phone");
@@ -405,7 +405,7 @@ static pjsip_uri *create_uri5(pj_pool_t *pool)
static pjsip_uri *create_uri6(pj_pool_t *pool)
{
/* "sips:localhost" */
- pjsip_sip_uri *url = pjsip_url_create(pool, 1);
+ pjsip_sip_uri *url = pjsip_sip_uri_create(pool, 1);
pj_strdup2(pool, &url->host, "localhost");
return (pjsip_uri*)url;
@@ -417,7 +417,7 @@ static pjsip_uri *create_uri7(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &url->host, "localhost");
@@ -430,7 +430,7 @@ static pjsip_uri *create_uri8(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 1);
+ url = pjsip_sip_uri_create(pool, 1);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Power Administrator");
@@ -444,7 +444,7 @@ static pjsip_uri *create_uri9(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "User");
@@ -460,7 +460,7 @@ static pjsip_uri *create_uri10(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Strange User\\\"\\\\\\\"");
@@ -474,7 +474,7 @@ static pjsip_uri *create_uri11(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Rogue User\\");
@@ -488,7 +488,7 @@ static pjsip_uri *create_uri12(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "Strange User\"");
@@ -500,7 +500,7 @@ static pjsip_uri *create_uri13(pj_pool_t *pool)
{
/* "sip:localhost;pvalue=\"hello world\"" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "localhost");
//pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
param_add(url->other_param, "pvalue", "hello world");
@@ -513,7 +513,7 @@ static pjsip_uri *create_uri14(pj_pool_t *pool)
pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
name_addr->uri = (pjsip_uri*) url;
pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");
@@ -528,7 +528,7 @@ static pjsip_uri *create_uri15(pj_pool_t *pool)
{
/* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
return (pjsip_uri*)url;
}
@@ -537,7 +537,7 @@ static pjsip_uri *create_uri16(pj_pool_t *pool)
{
/* "sip:" USER_CHAR ":" PASS_CHAR "@host" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->user, USER_CHAR);
pj_strdup2(pool, &url->passwd, PASS_CHAR);
pj_strdup2(pool, &url->host, "host");
@@ -548,7 +548,7 @@ static pjsip_uri *create_uri17(pj_pool_t *pool)
{
/* "sip:host;user=ip;" PARAM_CHAR "%21=" PARAM_CHAR "%21;lr;other=1;transport=sctp;other2" */
pjsip_sip_uri *url;
- url = pjsip_url_create(pool, 0);
+ url = pjsip_sip_uri_create(pool, 0);
pj_strdup2(pool, &url->host, "host");
pj_strdup2(pool, &url->user_param, "ip");
pj_strdup2(pool, &url->transport_param, "sctp");
diff --git a/svn_add b/svn_add
new file mode 100644
index 00000000..ef10dd05
--- /dev/null
+++ b/svn_add
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+svn add $1
+svn pset svn:keywords id $1
+svn pset svn:eol-style native $1
+