summaryrefslogtreecommitdiff
path: root/pjsip/src
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 /pjsip/src
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
Diffstat (limited to 'pjsip/src')
-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
26 files changed, 2374 insertions, 2522 deletions
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");