📄 sip_dialog.c
字号:
sstate = sip_get_substate((sip_msg_t)sip_msg, &error); if (sstate == NULL || error != 0) { return (NULL); } if ((sstate->sip_str_len != strlen("pending") && sstate->sip_str_len != strlen("active")) || ((sstate->sip_str_len == strlen("pending") && strncasecmp(sstate->sip_str_ptr, "pending", strlen("pending")) != 0) || (sstate->sip_str_len == strlen("active") && strncasecmp(sstate->sip_str_ptr, "active", strlen("active")) != 0))) { return (NULL); } ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); } else { if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, SIP_DLG_XCHG_TO); } else { (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); thdr = sip_search_for_header(sip_msg, SIP_TO, NULL); (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); } if (thdr == NULL) { (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); return (NULL); } ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL); } if (ttag == NULL) return (NULL); prev_state = dialog->sip_dlg_state; if (method == NOTIFY) { int error; const sip_str_t *dlg_id_val = NULL; const sip_str_t *event; const sip_str_t *id_val = NULL; sip_header_value_t ev_val; sip_hdr_value_t *dlg_ev_val = NULL; event = sip_get_event((sip_msg_t)sip_msg, &error); if (event == NULL || error != 0) return (NULL); ev_val = (sip_header_value_t)sip_get_header_value(evhdr, &error); if (ev_val != NULL) id_val = sip_get_param_value(ev_val, "id", &error); if (error == 0) { dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value( dialog->sip_dlg_event, &error); } if (dlg_ev_val == NULL || error != 0) return (NULL); dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val, "id", &error); if (error != 0 || dlg_ev_val->str_val_len != event->sip_str_len || strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr, event->sip_str_len != 0)) { return (NULL); } if ((dlg_id_val == NULL && id_val != NULL) || (dlg_id_val != NULL && id_val == NULL)) { return (NULL); } else if (dlg_id_val != NULL && id_val != NULL) { if (dlg_id_val->sip_str_len != id_val->sip_str_len || strncasecmp(dlg_id_val->sip_str_ptr, id_val->sip_str_ptr, dlg_id_val->sip_str_len) != 0) { return (NULL); } } dialog->sip_dlg_state = SIP_DLG_CONFIRMED; if (dialog->sip_dlg_type == SIP_UAC_DIALOG) dialog->sip_dlg_remote_uri_tag = thdr; else dialog->sip_dlg_local_uri_tag = thdr; } else { resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error); (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); assert(dialog->sip_dlg_state == SIP_DLG_NEW); if (SIP_PROVISIONAL_RESP(resp_code)) { dialog->sip_dlg_state = SIP_DLG_EARLY; } else if (SIP_OK_RESP(resp_code)) { dialog->sip_dlg_state = SIP_DLG_CONFIRMED; } else { dialog->sip_dlg_state = SIP_DLG_DESTROYED; (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); if (func != NULL) func(dialog, (sip_msg_t)sip_msg, NULL); sip_release_dialog_res(dialog); return (NULL); } if (dialog->sip_dlg_type == SIP_UAS_DIALOG) { dialog->sip_dlg_local_uri_tag = thdr; } else { if ((dialog->sip_dlg_remote_uri_tag = sip_dup_header(thdr)) == NULL) { (void) pthread_mutex_unlock( &dialog->sip_dlg_mutex); return (NULL); /* XXXDestroy dialog? */ } } } /* Cancel the partial dialog timer */ if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) SIP_CANCEL_TIMER(dialog->sip_dlg_timer); if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { val = sip_get_header_value(dialog->sip_dlg_local_uri_tag, &error); } else { val = sip_get_header_value(dialog->sip_dlg_remote_uri_tag, &error); } assert(val != NULL && error == 0); remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error); val = sip_get_header_value(dialog->sip_dlg_call_id, &error); callid = &((sip_hdr_value_t *)val)->str_val; /* Get an ID for this dialog */ if (dialog->sip_dlg_type == SIP_UAC_DIALOG) { sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len, ttag->sip_str_ptr, ttag->sip_str_len, callid->sip_str_ptr, callid->sip_str_len, NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); } else { sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len, remtag->sip_str_ptr, remtag->sip_str_len, callid->sip_str_ptr, callid->sip_str_len, NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); } SIP_DLG_REFCNT_INCR(dialog); (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); /* Add it to the hash table */ if (sip_hash_add(sip_dialog_hash, (void *)dialog, SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { sip_release_dialog_res(dialog); return (NULL); } if (sip_dlg_ulp_state_cb != NULL) { sip_dlg_ulp_state_cb((sip_dialog_t)dialog, (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state); } return ((sip_dialog_t)dialog);}/* * For a UAC just giving the RESPONSE/NOTIFY to the INVITE/SUBSCRIBE is enough, * we can get all the info. from it. However, on the UAS side we would need * the original request INVITE/SUBSCRIBE and the response RESPONSE/NOTIFY * since we don't have the remote target (CONTACT) info. in the response/notify. */sip_dialog_tsip_dialog_create(_sip_msg_t *resp, _sip_msg_t *req, int what){ _sip_dialog_t *dialog; _sip_header_t *fhdr; _sip_header_t *thdr; _sip_header_t *chdr; _sip_header_t *cihdr; const sip_str_t *ltag; const sip_str_t *ttag; const sip_str_t *callid; int cseq; const struct sip_value *value; int resp_code; int error = 0; int prev_state; sip_method_t method = 0; if (what == SIP_UAS_DIALOG) { if (req == NULL || !sip_msg_is_request((sip_msg_t)req, &error) || error != 0 || (sip_get_request_method((sip_msg_t)req, &error) != INVITE && sip_get_request_method((sip_msg_t)req, &error) != SUBSCRIBE)) { return (NULL); } } if (sip_msg_is_request((sip_msg_t)resp, &error)) { /* Only NOTIFY request can create a dialog */ method = sip_get_request_method((sip_msg_t)resp, &error); if (method != NOTIFY) return (NULL); } else { /* Only response to an INVITE/SUBSCRIBE can create a dialog */ resp_code = sip_get_response_code((sip_msg_t)resp, &error); if (error == 0) { method = sip_get_callseq_method((sip_msg_t)resp, &error); } if (error != 0 || (!SIP_PROVISIONAL_RESP(resp_code) && !SIP_OK_RESP(resp_code)) || (method != INVITE && method != SUBSCRIBE)) { return (NULL); } } (void) pthread_mutex_lock(&resp->sip_msg_mutex); if (what == SIP_UAS_DIALOG) { if (method == NOTIFY) { fhdr = sip_search_for_header(resp, SIP_FROM, NULL); thdr = sip_search_for_header(resp, SIP_TO, NULL); } else { fhdr = sip_search_for_header(resp, SIP_TO, NULL); thdr = sip_search_for_header(resp, SIP_FROM, NULL); } (void) pthread_mutex_lock(&req->sip_msg_mutex); chdr = sip_search_for_header(req, SIP_CONTACT, NULL); (void) pthread_mutex_unlock(&req->sip_msg_mutex); } else { if (method == NOTIFY) { thdr = sip_search_for_header(resp, SIP_FROM, NULL); fhdr = sip_search_for_header(resp, SIP_TO, NULL); } else { fhdr = sip_search_for_header(resp, SIP_FROM, NULL); thdr = sip_search_for_header(resp, SIP_TO, NULL); } chdr = sip_search_for_header(resp, SIP_CONTACT, NULL); } cihdr = sip_search_for_header(resp, SIP_CALL_ID, NULL); (void) pthread_mutex_unlock(&resp->sip_msg_mutex); if (fhdr == NULL || thdr == NULL || cihdr == NULL) return (NULL); /* Sanity check since we just store the headers in the dialog */ if (((ltag = sip_get_from_tag((sip_msg_t)resp, NULL)) == NULL) || sip_get_from_uri_str((sip_msg_t)resp, NULL) == NULL || ((ttag = sip_get_to_tag((sip_msg_t)resp, NULL)) == NULL) || sip_get_to_uri_str((sip_msg_t)resp, NULL) == NULL || ((cseq = sip_get_callseq_num((sip_msg_t)resp, NULL)) == -1) || ((callid = sip_get_callid((sip_msg_t)resp, NULL)) == NULL) || ((value = sip_get_header_value(chdr, NULL)) == NULL) || sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { return (NULL); } dialog = calloc(1, sizeof (_sip_dialog_t)); if (dialog == NULL) return (NULL); dialog->sip_dlg_local_cseq = cseq; dialog->sip_dlg_type = what; dialog->sip_dlg_method = method == NOTIFY ? SUBSCRIBE : method; /* this is just 0 */ prev_state = dialog->sip_dlg_state; if ((dialog->sip_dlg_remote_uri_tag = sip_dup_header(thdr)) == NULL || (dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == NULL || (dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL || (dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) { goto error; } dialog->sip_dlg_rset.sip_str_ptr = NULL; dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_req_uri.sip_str_ptr = NULL; dialog->sip_dlg_req_uri.sip_str_len = 0; if (sip_dialog_get_route_set(dialog, resp, what) != 0) goto error; /* Get an ID for this dialog */ sip_md5_hash(ltag->sip_str_ptr, ltag->sip_str_len, ttag->sip_str_ptr, ttag->sip_str_len, callid->sip_str_ptr, callid->sip_str_len, NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); SIP_DLG_REFCNT_INCR(dialog); (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); /* Add it to the hash table */ if (sip_hash_add(sip_dialog_hash, (void *)dialog, SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { sip_release_dialog_res(dialog); return (NULL); } if (sip_dlg_ulp_state_cb != NULL) { sip_dlg_ulp_state_cb((sip_dialog_t)dialog, (sip_msg_t)resp, prev_state, dialog->sip_dlg_state); } return ((sip_dialog_t)dialog);error: sip_release_dialog_res(dialog); return (NULL);}/* * Check if this dialog is a match. */boolean_tsip_dialog_match(void *obj, void *hindex){ _sip_dialog_t *dialog = (_sip_dialog_t *)obj; (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) { (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_FALSE); } if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) == 0) { SIP_DLG_REFCNT_INCR(dialog); (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_TRUE); } (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_FALSE);}/* Don't delete, just take it out of the hash */boolean_tsip_dialog_dontfree(void *obj, void *hindex, int *found){ _sip_dialog_t *dialog = (_sip_dialog_t *)obj; *found = 0; (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) == 0) { *found = 1; (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_TRUE); } (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_FALSE);}/* * Free resources associated with the dialog, the object will be removed * from the hash list by sip_hash_delete. */boolean_tsip_dialog_free(void *obj, void *hindex, int *found){ _sip_dialog_t *dialog = (_sip_dialog_t *)obj; *found = 0; (void) pthread_mutex_lock(&dialog->sip_dlg_mutex); if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id)) == 0) { *found = 1; assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED); if (dialog->sip_dlg_ref_cnt != 0) { (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_FALSE); } (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); sip_release_dialog_res(dialog); return (B_TRUE); } (void) pthread_mutex_unlock(&dialog->sip_dlg_mutex); return (B_FALSE);}/* * The UAS will receive the request from the transaction layer. If the * request has a tag in the To header field, the UAS core computes the * dialog identifier corresponding to the request and compares it with * existing dialogs. If there is a match, this is a mid-dialog request. */sip_dialog_tsip_dialog_find(_sip_msg_t *sip_msg){ const sip_str_t *localtag; const sip_str_t *remtag; const sip_str_t *callid; uint16_t digest[8]; _sip_dialog_t *dialog; boolean_t is_request; int error; is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error); if (error != 0) return (NULL); if (is_request) { localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); if (error == 0) remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error); } else { remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error); if (error == 0) localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -