📄 sip_dialog.c
字号:
/* $Id: sip_dialog.c 1027 2007-03-01 18:41:36Z bennylp $ *//* * Copyright (C) 2003-2007 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"long pjsip_dlg_lock_tls_id;PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m){ const pjsip_method subscribe = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}}; const pjsip_method refer = { PJSIP_OTHER_METHOD, {"REFER", 5}}; const pjsip_method notify = { PJSIP_OTHER_METHOD, {"NOTIFY", 6}}; return m->id == PJSIP_INVITE_METHOD || (pjsip_method_cmp(m, &subscribe)==0) || (pjsip_method_cmp(m, &refer)==0) || (pjsip_method_cmp(m, ¬ify)==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_ansi_snprintf(dlg->obj_name, sizeof(dlg->obj_name), "dlg%p", dlg); dlg->ua = ua; dlg->endpt = endpt; dlg->state = PJSIP_DIALOG_STATE_NULL; pj_list_init(&dlg->inv_hdr); status = pj_mutex_create_recursive(pool, dlg->obj_name, &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_); dlg->mutex_ = NULL; } if (dlg->tp_sel.type != PJSIP_TPSELECTOR_NONE) { pjsip_tpselector_dec_ref(&dlg->tp_sel); pj_bzero(&dlg->tp_sel, sizeof(pjsip_tpselector)); } pjsip_endpt_release_pool(dlg->endpt, 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; } /* Put any header param in the target URI into INVITE header list. */ if (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target)) { pjsip_param *param; pjsip_sip_uri *uri = (pjsip_sip_uri*)pjsip_uri_get_uri(dlg->target); param = uri->header_param.next; while (param != &uri->header_param) { pjsip_hdr *hdr; int c; c = param->value.ptr[param->value.slen]; param->value.ptr[param->value.slen] = '\0'; hdr = pjsip_parse_hdr(dlg->pool, ¶m->name, param->value.ptr, param->value.slen, NULL); param->value.ptr[param->value.slen] = (char)c; if (hdr == NULL) { status = PJSIP_EINVALIDURI; goto on_error; } pj_list_push_back(&dlg->inv_hdr, hdr); param = param->next; } /* Now must remove any header params from URL, since that would * create another header in pjsip_endpt_create_request(). */ pj_list_init(&uri->header_param); } /* Init local info. */ dlg->local.info = pjsip_from_hdr_create(dlg->pool); pj_strdup_with_null(dlg->pool, &dlg->local.info_str, local_uri); dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.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.first_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, &dlg->remote.info_str, remote_uri); dlg->remote.info->uri = pjsip_parse_uri(dlg->pool, dlg->remote.info_str.ptr, dlg->remote.info_str.slen, 0); if (!dlg->remote.info->uri) { status = PJSIP_EINVALIDURI; goto on_error; } /* Remove header param from remote.info_str, if any */ if (PJSIP_URI_SCHEME_IS_SIP(dlg->remote.info->uri) || PJSIP_URI_SCHEME_IS_SIPS(dlg->remote.info->uri)) { pjsip_sip_uri *sip_uri = pjsip_uri_get_uri(dlg->remote.info->uri); if (!pj_list_empty(&sip_uri->header_param)) { pj_str_t tmp; /* Remove all header param */ pj_list_init(&sip_uri->header_param); /* Print URI */ tmp.ptr = pj_pool_alloc(dlg->pool, dlg->remote.info_str.slen); tmp.slen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_uri, tmp.ptr, dlg->remote.info_str.slen); if (tmp.slen < 1) { status = PJSIP_EURITOOLONG; goto on_error; } /* Assign remote.info_str */ dlg->remote.info_str = tmp; } } /* 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, dlg->endpt, 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; PJ_LOG(5,(dlg->obj_name, "UAC dialog created")); 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_transaction *tsx = NULL; pj_str_t tmp; enum { TMP_LEN=128}; pj_ssize_t len; 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; /* Temprary string for getting the string representation of * both local and remote URI. */ tmp.ptr = pj_pool_alloc(rdata->tp_info.pool, TMP_LEN); /* 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); /* Print the local info. */ len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, tmp.ptr, TMP_LEN); if (len < 1) { pj_ansi_strcpy(tmp.ptr, "<-error: uri too long->"); tmp.slen = pj_ansi_strlen(tmp.ptr); } else tmp.slen = len; /* Save the local info. */ pj_strdup(dlg->pool, &dlg->local.info_str, &tmp); /* 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); /* Print the remote info. */ len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, dlg->remote.info->uri, tmp.ptr, TMP_LEN); if (len < 1) { pj_ansi_strcpy(tmp.ptr, "<-error: uri too long->"); tmp.slen = pj_ansi_strlen(tmp.ptr); } else tmp.slen = len; /* Save the remote info. */ pj_strdup(dlg->pool, &dlg->remote.info_str, &tmp); /* 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) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -