⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_dialog.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
		  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 == (void*)&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, dlg->endpt,
				 dlg->pool, 0);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Create UAS transaction for this request. */
    status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Associate this dialog to the transaction. */
    tsx->mod_data[dlg->ua->id] = dlg;

    /* Increment tsx counter */
    ++dlg->tsx_count;

    /* 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);

    /* Feed the first request to the transaction. */
    pjsip_tsx_recv_msg(tsx, rdata);

    /* Done. */
    *p_dlg = dlg;
    PJ_LOG(5,(dlg->obj_name, "UAS dialog created"));
    return PJ_SUCCESS;

on_error:
    if (tsx) {
	pjsip_tsx_terminate(tsx, 500);
	--dlg->tsx_count;
    }

    destroy_dialog(dlg);
    return status;
}


/*
 * Bind dialog to a specific transport/listener.
 */
PJ_DEF(pj_status_t) pjsip_dlg_set_transport( pjsip_dialog *dlg,
					     const pjsip_tpselector *sel)
{
    /* Validate */
    PJ_ASSERT_RETURN(dlg && sel, PJ_EINVAL);

    /* Start locking the dialog. */
    pjsip_dlg_inc_lock(dlg);

    /* Decrement reference counter of previous transport selector */
    pjsip_tpselector_dec_ref(&dlg->tp_sel);

    /* Copy transport selector structure .*/
    pj_memcpy(&dlg->tp_sel, sel, sizeof(*sel));

    /* Increment reference counter */
    pjsip_tpselector_add_ref(&dlg->tp_sel);

    /* Unlock dialog. */
    pjsip_dlg_dec_lock(dlg);

    return PJ_SUCCESS;
}


/*
 * 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);

    /* Status code MUST be 1xx (but not 100), or 2xx */
    status = rdata->msg_info.msg->line.status.code;
    PJ_ASSERT_RETURN( (status/100==1 && status!=100) ||
		      (status/100==2), PJ_EBUG);

    /* 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;

    /* Dialog state depends on the response. */
    status = rdata->msg_info.msg->line.status.code/100;
    if (status == 1 || status == 2)
	dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
    else {
	pj_assert(!"Invalid status code");
	dlg->state = PJSIP_DIALOG_STATE_NULL;
    }

    /* 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;
    }

    /* Clone 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;

    PJ_LOG(5,(dlg->obj_name, "Forked dialog created"));
    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;
    }

    /* Log */
    PJ_LOG(5,(dlg->obj_name, "Dialog destroyed"));

    /* Destroy this dialog. */
    destroy_dialog(dlg);

    return PJ_SUCCESS;
}


/*
 * Forcefully terminate dialog.
 */
PJ_DEF(pj_status_t) pjsip_dlg_terminate( pjsip_dialog *dlg )
{
    /* 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);

    return unregister_and_destroy_dialog(dlg);
}


/*
 * 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);

    pjsip_dlg_inc_lock(dlg);

    /* Clear route set. */
    pj_list_init(&dlg->route_set);

    if (!route_set) {
	pjsip_dlg_dec_lock(dlg);
	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;
    }

    pjsip_dlg_dec_lock(dlg);
    return PJ_SUCCESS;
}


/*
 * Increment session counter.
 */
PJ_DEF(pj_status_t) pjsip_dlg_inc_session( pjsip_dialog *dlg,
					   pjsip_module *mod )
{
    PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);

    pjsip_dlg_inc_lock(dlg);
    ++dlg->sess_count;
    pjsip_dlg_dec_lock(dlg);

    PJ_LOG(5,(dlg->obj_name, "Session count inc to %d by %.*s",
	      dlg->sess_count, (int)mod->name.slen, mod->name.ptr));

    return PJ_SUCCESS;
}

/*
 * Lock dialog and increment session counter temporarily
 * to prevent it from being deleted. In addition, it must lock
 * the user agent's dialog table first, to prevent deadlock.
 */
PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg)
{
    PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_inc_lock(), sess_count=%d", 
	      dlg->sess_count));

    pj_mutex_lock(dlg->mutex_);
    dlg->sess_count++;

    PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_inc_lock(), sess_count=%d", 
	      dlg->sess_count));
}

/* Try to acquire dialog's mutex, but bail out if mutex can not be
 * acquired immediately.
 */
PJ_DEF(pj_status_t) pjsip_dlg_try_inc_lock(pjsip_dialog *dlg)
{
    pj_status_t status;

    PJ_LOG(6,(dlg->obj_name,"Entering pjsip_dlg_try_inc_lock(), sess_count=%d", 
	      dlg->sess_count));

    status = pj_mutex_trylock(dlg->mutex_);
    if (status != PJ_SUCCESS) {
	PJ_LOG(6,(dlg->obj_name, "pjsip_dlg_try_inc_lock() failed"));
	return status;
    }

    dlg->sess_count++;

    PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_try_inc_lock(), sess_count=%d", 
	      dlg->sess_count));

    return PJ_SUCCESS;
}


/*
 * Unlock dialog and decrement session counter.
 * It may delete the dialog!
 */
PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg)
{
    PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_dec_lock(), sess_count=%d", 
	      dlg->sess_count));

    pj_assert(dlg->sess_count > 0);
    --dlg->sess_count;

    if (dlg->sess_count==0 && dlg->tsx_count==0) {
	pj_mutex_unlock(dlg->mutex_);
	pj_mutex_lock(dlg->mutex_);
	unregister_and_destroy_dialog(dlg);
    } else {
	pj_mutex_unlock(dlg->mutex_);
    }

    PJ_LOG(6,(THIS_FILE, "Leaving pjsip_dlg_dec_lock() (dlg=%p)", dlg));
}



/*
 * Decrement session counter.
 */
PJ_DEF(pj_status_t) pjsip_dlg_dec_session( pjsip_dialog *dlg,
					   pjsip_module *mod)
{
    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);

    PJ_LOG(5,(dlg->obj_name, "Session count dec to %d by %.*s",
	      dlg->sess_count-1, (int)mod->name.slen, mod->name.ptr));

    pjsip_dlg_inc_lock(dlg);
    --dlg->sess_count;
    pjsip_dlg_dec_lock(dlg);

    return PJ_SUCCESS;
}

/*
 * 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_LOG(5,(dlg->obj_name, 
	      "Module %.*s added as dialog usage, data=%p",
	      (int)mod->name.slen, mod->name.ptr, mod_data));

    pjsip_dlg_inc_lock(dlg);

    /* 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.
     */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -