📄 sip_dialog.c
字号:
dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] = '\0'; if (uri != NULL) { if (first) { count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT, uri, SIP_RAQUOT); } else { count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA, SIP_LAQUOT, uri, SIP_RAQUOT); } rp += count; rpl -= count; free(uri); } assert(rp <= rset + rset_len); (void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1, "%s%s", rset, SIP_CRLF); free(rset); dialog->sip_dlg_route_set = (sip_header_t)rhdr; sip_dialog_free_rset(rset_head); return (0);}/* * UAC Behavior * The route set MUST be set to the list of URIs in the Record-Route * header field from the response, taken in reverse order and preserving * all URI parameters. * * UAS behavior * 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. */static intsip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what){ sip_header_t rrhdr; sip_hdr_value_t *value; int error; sip_dlg_route_set_t *rset_head = NULL; sip_dlg_route_set_t *rset_tail = NULL; sip_dlg_route_set_t *rset; int rset_cnt = 0; int rset_len = 0; (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL); while (rrhdr != NULL) { (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error); while (value != NULL && error == 0) { char *crlf; if (value->sip_value_state == SIP_VALUE_BAD) { value = (sip_hdr_value_t *)sip_get_next_value( (sip_header_value_t)value, &error); continue; } rset = sip_add_route_to_set(value); if (rset == NULL) goto r_error; /* Add one for COMMA */ rset_cnt++; rset_len += (value->sip_value_end - value->sip_value_start); /* Check for CRLF */ crlf = value->sip_value_end - strlen(SIP_CRLF); while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { rset_len -= strlen(SIP_CRLF); crlf -= strlen(SIP_CRLF); } if (rset_head == NULL) { assert(rset_tail == NULL); rset_head = rset_tail = rset; } else if (what == SIP_UAS_DIALOG) { rset_tail->sip_dlg_route_next = rset; rset_tail = rset; } else if (what == SIP_UAC_DIALOG) { rset->sip_dlg_route_next = rset_head; rset_head = rset; } else { assert(0); } value = (sip_hdr_value_t *)sip_get_next_value( (sip_header_value_t)value, &error); } (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr); } (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); if (rset_cnt == 0) return (0); if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt, rset_len) != 0) { goto r_error; } return (0);r_error: sip_dialog_free_rset(rset_head); return (ENOMEM);}/* * UAS behavior: * The remote sequence number MUST be set to the value of the sequence * number in the CSeq header field of the request. The local sequence * number MUST be empty. The call identifier component of the dialog ID * MUST be set to the value of the Call-ID in the request. The local * tag component of the dialog ID MUST be set to the tag in the To field * in the response to the request (which always includes a tag), and the * remote tag component of the dialog ID MUST be set to the tag from the * From field in the request. A UAS MUST be prepared to receive a * request without a tag in the From field, in which case the tag is * considered to have a value of null. * The remote URI MUST be set to the URI in the From field, and the * local URI MUST be set to the URI in the To field. * The remote target MUST be set to the URI from the Contact header field * of the request. * * UAC behavior: * The local sequence number MUST be set to the value of the sequence * number in the CSeq header field of the request. The remote sequence * number MUST be empty (it is established when the remote UA sends a * request within the dialog). The call identifier component of the * dialog ID MUST be set to the value of the Call-ID in the request. * The local tag component of the dialog ID MUST be set to the tag in * the From field in the request, and the remote tag component of the * dialog ID MUST be set to the tag in the To field of the response. A * UAC MUST be prepared to receive a response without a tag in the To * field, in which case the tag is considered to have a value of null. * The remote URI MUST be set to the URI in the To field, and the local * URI MUST be set to the URI in the From field. * The remote target MUST be set to the URI from the Contact header field * of the response. *//* * This is the routine that seeds a dialog. */sip_dialog_tsip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg, void (*func)(sip_dialog_t, sip_msg_t, void *), boolean_t dlg_on_fork, int dlg_type){ _sip_dialog_t *dialog; int cseq; sip_header_t fhdr = NULL; sip_header_t thdr = NULL; sip_header_t chdr; sip_header_t cihdr; sip_header_t evhdr = NULL; const struct sip_value *value; sip_dialog_timer_obj_t *tim_obj = NULL; const sip_str_t *callid; sip_method_t method; int timer1 = sip_timer_T1; int error; if (!sip_msg_is_request((sip_msg_t)sip_msg, &error)) return (NULL); method = sip_get_request_method((sip_msg_t)sip_msg, &error); /* Only INVITE and SUBSCRIBE supported */ if (error != 0 || (method != INVITE && method != SUBSCRIBE)) return (NULL); if (dlg_type == SIP_UAS_DIALOG) { thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, SIP_DLG_XCHG_FROM); (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); } else { (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL); } cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL); chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL); if (method == SUBSCRIBE) evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL || (method == SUBSCRIBE && evhdr == NULL)) { return (NULL); } /* Sanity check since we just store the headers in the dialog */ if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL || sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL || ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) || (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL || sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL || ((value = sip_get_header_value(chdr, NULL)) == NULL) || sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) { return (NULL); } tim_obj = malloc(sizeof (sip_dialog_timer_obj_t)); if (tim_obj == NULL) return (NULL); dialog = calloc(1, sizeof (_sip_dialog_t)); if (dialog == NULL) return (NULL); /* * We will take the TO header with the tag when we complete this * dialog */ if (dlg_type == SIP_UAS_DIALOG) { dialog->sip_dlg_remote_uri_tag = thdr; } else { if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) == NULL) { goto dia_err; } } if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL || (dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL) { goto dia_err; } if (method == SUBSCRIBE) { dialog->sip_dlg_event = sip_dup_header(evhdr); if (dialog->sip_dlg_event == NULL) { goto dia_err; } } 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; /* Get the route set from the request, if present */ if (sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) { goto dia_err; } if (dlg_type == SIP_UAC_DIALOG) dialog->sip_dlg_local_cseq = cseq; else dialog->sip_dlg_remote_cseq = cseq; dialog->sip_dlg_type = dlg_type; dialog->sip_dlg_on_fork = dlg_on_fork; dialog->sip_dlg_method = method; /* Set the partial dialog timer with the INVITE timeout val */ if (sip_conn_timer1 != NULL) timer1 = sip_conn_timer1(obj); SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1); tim_obj->dialog = dialog; tim_obj->func = func; SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj, sip_dlg_self_destruct); if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) goto dia_err; (void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL); if (dlg_type == SIP_UAC_DIALOG) { const sip_str_t *local_tag; local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL); assert(local_tag != NULL); sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len, callid->sip_str_ptr, callid->sip_str_len, NULL, 0, NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id); SIP_DLG_REFCNT_INCR(dialog); /* Add it to the partial hash table */ if (sip_hash_add(sip_dialog_phash, (void *)dialog, SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) { goto dia_err; } } return ((sip_dialog_t)dialog);dia_err: sip_release_dialog_res(dialog); if (tim_obj != NULL) free(tim_obj); return (NULL);}/* * When creating a dialog from a NOTIFY request, we need to get the FROM * header for the dialog from the TO header of the NOTIFY. */_sip_header_t *sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what){ int len; _sip_header_t *newhdr; int cnt; const struct sip_header *hdr; int hdrsize; int error; hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM : SIP_TO, NULL, &error); if (error != 0 || hdr == NULL) return (NULL); if (sip_parse_goto_values((_sip_header_t *)hdr) != 0) return (NULL); len = hdr->sip_hdr_end - hdr->sip_hdr_current; if (what == SIP_DLG_XCHG_FROM) { hdrsize = len + strlen(SIP_TO) + SIP_SPACE + sizeof (char) + SIP_SPACE; } else { hdrsize = len + strlen(SIP_FROM) + SIP_SPACE + sizeof (char) + SIP_SPACE; } newhdr = sip_new_header(hdrsize); if (newhdr == NULL) return (NULL); if (what == SIP_DLG_XCHG_FROM) { cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, "%s %c ", SIP_TO, SIP_HCOLON); } else { cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1, "%s %c ", SIP_FROM, SIP_HCOLON); } newhdr->sip_hdr_current += cnt; (void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len); newhdr->sip_hdr_current += len; assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end); assert(hdr->sip_header_functions != NULL); /* FROM and TO have common parsing functions */ newhdr->sip_header_functions = hdr->sip_header_functions; newhdr->sip_hdr_current = newhdr->sip_hdr_start; return (newhdr);}/* * This is the response that completes the dialog that was created * in sip_seed_dialog(). */sip_dialog_tsip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog, void (*func)(sip_dialog_t, sip_msg_t, void *)){ _sip_header_t *thdr; _sip_header_t *evhdr = NULL; _sip_header_t *substate = NULL; int resp_code; const sip_str_t *ttag; const sip_str_t *remtag; const sip_str_t *callid; const struct sip_value *val; sip_method_t method; int error = 0; int prev_state; if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0) method = sip_get_request_method((sip_msg_t)sip_msg, &error); else method = sip_get_callseq_method((sip_msg_t)sip_msg, &error); if (error != 0 || dialog == NULL || (sip_msg_is_request((sip_msg_t)sip_msg, &error) && (dialog->sip_dlg_method == INVITE || method != NOTIFY))) { return (NULL); } if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY && sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != dialog->sip_dlg_local_cseq) || (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY && sip_get_callseq_num((sip_msg_t)sip_msg, NULL) != dialog->sip_dlg_remote_cseq)) { return (NULL); } if (method == NOTIFY) { const sip_str_t *sstate; thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg, SIP_DLG_XCHG_FROM); (void) pthread_mutex_lock(&sip_msg->sip_msg_mutex); evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL); if (evhdr == NULL) { (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); return (NULL); } substate = sip_search_for_header(sip_msg, SIP_SUBSCRIPTION_STATE, NULL); if (substate == NULL) { (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex); return (NULL); } (void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -