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