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

📄 sip_dialog.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
    for (index=0; index<dlg->usage_cnt; ++index) {
	if (dlg->usage[index] == mod) {
	    /* Module may be registered more than once in the same dialog.
	     * For example, when call transfer fails, application may retry
	     * call transfer on the same dialog.
	     * So return PJ_SUCCESS here.
	     */
	    PJ_LOG(4,(dlg->obj_name, 
		      "Module %.*s already registered as dialog usage, "
		      "updating the data %p",
		      (int)mod->name.slen, mod->name.ptr, mod_data));
	    dlg->mod_data[mod->id] = mod_data;

	    pjsip_dlg_dec_lock(dlg);
	    return PJ_SUCCESS;

	    //pj_assert(!"This module is already registered");
	    //pjsip_dlg_dec_lock(dlg);
	    //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;

    /* Increment count. */
    ++dlg->usage_cnt;

    pjsip_dlg_dec_lock(dlg);

    return PJ_SUCCESS;
}


/*
 * Attach module specific data to the dialog. Application can also set 
 * the value directly by accessing dlg->mod_data[module_id].
 */
PJ_DEF(pj_status_t) pjsip_dlg_set_mod_data( pjsip_dialog *dlg,
					    int mod_id,
					    void *data )
{
    PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
    PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
		     PJ_EINVAL);
    dlg->mod_data[mod_id] = data;
    return PJ_SUCCESS;
}

/**
 * Get module specific data previously attached to the dialog. Application
 * can also get value directly by accessing dlg->mod_data[module_id].
 */
PJ_DEF(void*) pjsip_dlg_get_mod_data( pjsip_dialog *dlg,
				      int mod_id)
{
    PJ_ASSERT_RETURN(dlg, NULL);
    PJ_ASSERT_RETURN(mod_id >= 0 && mod_id < PJSIP_MAX_MODULE,
		     NULL);
    return dlg->mod_data[mod_id];
}


/*
 * 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(dlg->endpt,
						 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, if request is not ACK or CANCEL. */
    if (method->id != PJSIP_ACK_METHOD && method->id != PJSIP_CANCEL_METHOD) {
	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. */
    pjsip_dlg_inc_lock(dlg);

    /* 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. */
    pjsip_dlg_dec_lock(dlg);

    *p_tdata = tdata;

    return status;
}


/*
 * Send request statefully, and update dialog'c CSeq.
 */
PJ_DEF(pj_status_t) pjsip_dlg_send_request( pjsip_dialog *dlg,
					    pjsip_tx_data *tdata,
					    int mod_data_id,
					    void *mod_data)
{
    pjsip_transaction *tsx;
    pjsip_msg *msg = tdata->msg;
    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);

    PJ_LOG(5,(dlg->obj_name, "Sending %s",
	      pjsip_tx_data_get_info(tdata)));

    /* Lock and increment session */
    pjsip_dlg_inc_lock(dlg);

    /* 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_RETURN(ch!=NULL, PJ_EBUG);

	ch->cseq = dlg->local.cseq++;

	/* Force the whole message to be re-printed. */
	pjsip_tx_data_invalidate_msg( tdata );
    }

    /* Create a new transaction if method is not ACK.
     * The transaction user is the user agent module.
     */
    if (msg->line.req.method.id != PJSIP_ACK_METHOD) {
	int tsx_count;

	status = pjsip_tsx_create_uac(dlg->ua, tdata, &tsx);
	if (status != PJ_SUCCESS)
	    goto on_error;

	/* Set transport selector */
	status = pjsip_tsx_set_transport(tsx, &dlg->tp_sel);
	pj_assert(status == PJ_SUCCESS);

	/* Attach this dialog to the transaction, so that user agent
	 * will dispatch events to this dialog.
	 */
	tsx->mod_data[dlg->ua->id] = dlg;

	/* Copy optional caller's mod_data, if present */
	if (mod_data_id >= 0 && mod_data_id < PJSIP_MAX_MODULE)
	    tsx->mod_data[mod_data_id] = mod_data;

	/* Increment transaction counter. */
	tsx_count = ++dlg->tsx_count;

	/* Send the message. */
	status = pjsip_tsx_send_msg(tsx, tdata);
	if (status != PJ_SUCCESS) {
	    if (dlg->tsx_count == tsx_count)
		pjsip_tsx_terminate(tsx, tsx->status_code);
	    goto on_error;
	}

    } else {
	/* Set transport selector */
	pjsip_tx_data_set_transport(tdata, &dlg->tp_sel);

	/* Send request */
	status = pjsip_endpt_send_request_stateless(dlg->endpt, tdata, 
						    NULL, NULL);
	if (status != PJ_SUCCESS)
	    goto on_error;

    }

    /* Unlock dialog, may destroy dialog. */
    pjsip_dlg_dec_lock(dlg);

    return PJ_SUCCESS;

on_error:
    /* Unlock dialog, may destroy dialog. */
    pjsip_dlg_dec_lock(dlg);
   
    /* Whatever happen delete the message. */
    pjsip_tx_data_dec_ref( tdata );

    return status;
}

/* Add standard headers for certain types of response */
static void dlg_beautify_response(pjsip_dialog *dlg,
				  pj_bool_t add_headers,
				  int st_code,
				  pjsip_tx_data *tdata)
{
    pjsip_cseq_hdr *cseq;
    int st_class;
    const pjsip_hdr *c_hdr;
    pjsip_hdr *hdr;

    cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg);
    pj_assert(cseq != NULL);

    st_class = st_code / 100;

    /* Contact, Allow, Supported header. */
    if (add_headers && 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) 
	{
	    pj_str_t hcontact = { "Contact", 7 };

	    /* Add contact header only if one is not present. */
	    if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0 &&
		pjsip_msg_find_hdr_by_name(tdata->msg, &hcontact, NULL) == 0) 
	    {
		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) &&
	    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL) 
	{
	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
					       PJSIP_H_ALLOW, NULL);
	    if (c_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 && 
	    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL)==NULL) 
	{
	    c_hdr = pjsip_endpt_get_capability(dlg->endpt,
					       PJSIP_H_SUPPORTED, NULL);
	    if (c_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) {
	pjsip_to_hdr *to;

	to = PJSIP_MSG_TO_HDR(tdata->msg);
	pj_assert(to != NULL);

	to->tag = dlg->local.info->tag;

	if (dlg->state == PJSIP_DIALOG_STATE_NULL)
	    dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
    }
}


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

    /* Create generic response.
     * This will initialize response's Via, To, From, Call-ID, CSeq
     * and Record-Route headers from the request.
     */
    status = pjsip_endpt_create_response(dlg->endpt,
					 rdata, st_code, st_text, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Lock the dialog. */
    pjsip_dlg_inc_lock(dlg);

    dlg_beautify_response(dlg, PJ_FALSE, st_code, tdata);

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

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

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

    /* Lock and increment session */
    pjsip_dlg_inc_lock(dlg);

    /* Replace status code and reason */
    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);
    }

    /* Remove existing Contact header (without this, when dialog sent 
     * 180 and then 302, the Contact in 302 will not get updated).
     */
    hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
    if (hdr)
	pj_list_erase(hdr);

⌨️ 快捷键说明

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