📄 sip_dialog.c
字号:
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 + -