diff options
Diffstat (limited to 'pjsip/src/pjsip-ua/sip_ua.c')
-rw-r--r-- | pjsip/src/pjsip-ua/sip_ua.c | 473 |
1 files changed, 0 insertions, 473 deletions
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 -} - |