📄 sip_util.c
字号:
pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG && rdata->msg_info.msg->line.status.code >= 300); /* Initialize return value to NULL. */ *ack_tdata = NULL; /* The original INVITE message. */ invite_msg = tdata->msg; /* Get the headers from original INVITE request. */# define FIND_HDR(m,HNAME) pjsip_msg_find_hdr(m, PJSIP_H_##HNAME, NULL) from_hdr = (const pjsip_from_hdr*) FIND_HDR(invite_msg, FROM); PJ_ASSERT_ON_FAIL(from_hdr != NULL, goto on_missing_hdr); to_hdr = (const pjsip_to_hdr*) FIND_HDR(invite_msg, TO); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr); cid_hdr = (const pjsip_cid_hdr*) FIND_HDR(invite_msg, CALL_ID); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr); cseq_hdr = (const pjsip_cseq_hdr*) FIND_HDR(invite_msg, CSEQ); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);# undef FIND_HDR /* Create new request message from the headers. */ status = pjsip_endpt_create_request_from_hdr(endpt, &pjsip_ack_method, tdata->msg->line.req.uri, from_hdr, to_hdr, NULL, cid_hdr, cseq_hdr->cseq, NULL, &ack); if (status != PJ_SUCCESS) return status; /* Update tag in To header with the one from the response (if any). */ to = (pjsip_to_hdr*) pjsip_msg_find_hdr(ack->msg, PJSIP_H_TO, NULL); pj_strdup(ack->pool, &to->tag, &rdata->msg_info.to->tag); /* Clear Via headers in the new request. */ while ((via=pjsip_msg_find_hdr(ack->msg, PJSIP_H_VIA, NULL)) != NULL) pj_list_erase(via); /* Must contain single Via, just as the original INVITE. */ hdr = pjsip_msg_find_hdr( invite_msg, PJSIP_H_VIA, NULL); pjsip_msg_insert_first_hdr( ack->msg, pjsip_hdr_clone(ack->pool,hdr) ); /* If the original INVITE has Route headers, those header fields MUST * appear in the ACK. */ hdr = pjsip_msg_find_hdr( invite_msg, PJSIP_H_ROUTE, NULL); while (hdr != NULL) { pjsip_msg_add_hdr( ack->msg, pjsip_hdr_clone(ack->pool, hdr) ); hdr = hdr->next; if (hdr == &invite_msg->hdr) break; hdr = pjsip_msg_find_hdr( invite_msg, PJSIP_H_ROUTE, hdr); } /* We're done. * "tdata" parameter now contains the ACK message. */ *ack_tdata = ack; return PJ_SUCCESS;on_missing_hdr: if (ack) pjsip_tx_data_dec_ref(ack); return PJSIP_EMISSINGHDR;}/* * Construct CANCEL request for the previously sent request, according to * chapter 9.1 of RFC3261. */PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, const pjsip_tx_data *req_tdata, pjsip_tx_data **p_tdata){ pjsip_tx_data *cancel_tdata = NULL; const pjsip_from_hdr *from_hdr; const pjsip_to_hdr *to_hdr; const pjsip_cid_hdr *cid_hdr; const pjsip_cseq_hdr *cseq_hdr; const pjsip_hdr *hdr; pjsip_hdr *via; pj_status_t status; /* The transmit buffer must INVITE request. */ PJ_ASSERT_RETURN(req_tdata->msg->type == PJSIP_REQUEST_MSG && req_tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD, PJ_EINVAL); /* Get the headers from original INVITE request. */# define FIND_HDR(m,HNAME) pjsip_msg_find_hdr(m, PJSIP_H_##HNAME, NULL) from_hdr = (const pjsip_from_hdr*) FIND_HDR(req_tdata->msg, FROM); PJ_ASSERT_ON_FAIL(from_hdr != NULL, goto on_missing_hdr); to_hdr = (const pjsip_to_hdr*) FIND_HDR(req_tdata->msg, TO); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr); cid_hdr = (const pjsip_cid_hdr*) FIND_HDR(req_tdata->msg, CALL_ID); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr); cseq_hdr = (const pjsip_cseq_hdr*) FIND_HDR(req_tdata->msg, CSEQ); PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);# undef FIND_HDR /* Create new request message from the headers. */ status = pjsip_endpt_create_request_from_hdr(endpt, &pjsip_cancel_method, req_tdata->msg->line.req.uri, from_hdr, to_hdr, NULL, cid_hdr, cseq_hdr->cseq, NULL, &cancel_tdata); if (status != PJ_SUCCESS) return status; /* Clear Via headers in the new request. */ while ((via=pjsip_msg_find_hdr(cancel_tdata->msg, PJSIP_H_VIA, NULL)) != NULL) pj_list_erase(via); /* Must only have single Via which matches the top-most Via in the * request being cancelled. */ hdr = pjsip_msg_find_hdr(req_tdata->msg, PJSIP_H_VIA, NULL); if (hdr) { pjsip_msg_insert_first_hdr(cancel_tdata->msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); } /* If the original request has Route header, the CANCEL request must also * has exactly the same. * Copy "Route" header from the request. */ hdr = pjsip_msg_find_hdr(req_tdata->msg, PJSIP_H_ROUTE, NULL); while (hdr != NULL) { pjsip_msg_add_hdr(cancel_tdata->msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); hdr = hdr->next; if (hdr != &req_tdata->msg->hdr) hdr = pjsip_msg_find_hdr(req_tdata->msg, PJSIP_H_ROUTE, hdr); else break; } /* Done. * Return the transmit buffer containing the CANCEL request. */ *p_tdata = cancel_tdata; return PJ_SUCCESS;on_missing_hdr: if (cancel_tdata) pjsip_tx_data_dec_ref(cancel_tdata); return PJSIP_EMISSINGHDR;}/* * Find which destination to be used to send the request message, based * on the request URI and Route headers in the message. The procedure * used here follows the guidelines on sending the request in RFC 3261 * chapter 8.1.2. */PJ_DEF(pj_status_t) pjsip_get_request_dest(const pjsip_tx_data *tdata, pjsip_host_info *dest_info ){ const pjsip_uri *target_uri; const pjsip_route_hdr *first_route_hdr; PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL); /* Get the first "Route" header from the message. */ first_route_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL); if (first_route_hdr) { target_uri = first_route_hdr->name_addr.uri; } else { target_uri = tdata->msg->line.req.uri; } /* The target URI must be a SIP/SIPS URL so we can resolve it's address. * Otherwise we're in trouble (i.e. there's no host part in tel: URL). */ pj_bzero(dest_info, sizeof(*dest_info)); if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) { pjsip_uri *uri = (pjsip_uri*) target_uri; const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri); dest_info->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE); pj_strdup(tdata->pool, &dest_info->addr.host, &url->host); dest_info->addr.port = url->port; dest_info->type = pjsip_transport_get_type_from_name(&url->transport_param); } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) { pjsip_uri *uri = (pjsip_uri*) target_uri; const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri); pj_strdup(tdata->pool, &dest_info->addr.host, &url->host); dest_info->addr.port = url->port; dest_info->type = pjsip_transport_get_type_from_name(&url->transport_param); dest_info->flag = pjsip_transport_get_flag_from_type(dest_info->type); } else { pj_assert(!"Unsupported URI scheme!"); PJ_TODO(SUPPORT_REQUEST_ADDR_RESOLUTION_FOR_TEL_URI); return PJSIP_EINVALIDSCHEME; } return PJ_SUCCESS;}/* * Process route-set found in the request and calculate * the destination to be used to send the request message, based * on the request URI and Route headers in the message. The procedure * used here follows the guidelines on sending the request in RFC 3261 * chapter 8.1.2. */PJ_DEF(pj_status_t) pjsip_process_route_set(pjsip_tx_data *tdata, pjsip_host_info *dest_info ){ const pjsip_uri *new_request_uri, *target_uri; const pjsip_name_addr *topmost_route_uri; pjsip_route_hdr *first_route_hdr, *last_route_hdr; PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL); /* Find the first and last "Route" headers from the message. */ last_route_hdr = first_route_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL); if (first_route_hdr) { topmost_route_uri = &first_route_hdr->name_addr; while (last_route_hdr->next != (void*)&tdata->msg->hdr) { pjsip_route_hdr *hdr; hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, last_route_hdr->next); if (!hdr) break; last_route_hdr = hdr; } } else { topmost_route_uri = NULL; } /* If Route headers exist, and the first element indicates loose-route, * the URI is taken from the Request-URI, and we keep all existing Route * headers intact. * If Route headers exist, and the first element DOESN'T indicate loose * route, the URI is taken from the first Route header, and remove the * first Route header from the message. * Otherwise if there's no Route headers, the URI is taken from the * Request-URI. */ if (topmost_route_uri) { pj_bool_t has_lr_param; if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) || PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri)) { const pjsip_sip_uri *url = pjsip_uri_get_uri((void*)topmost_route_uri); has_lr_param = url->lr_param; } else { has_lr_param = 0; } if (has_lr_param) { new_request_uri = tdata->msg->line.req.uri; /* We shouldn't need to delete topmost Route if it has lr param. * But seems like it breaks some proxy implementation, so we * delete it anyway. */ /* pj_list_erase(first_route_hdr); if (first_route_hdr == last_route_hdr) last_route_hdr = NULL; */ } else { new_request_uri = pjsip_uri_get_uri((void*)topmost_route_uri); pj_list_erase(first_route_hdr); if (first_route_hdr == last_route_hdr) last_route_hdr = NULL; } target_uri = (pjsip_uri*)topmost_route_uri; } else { target_uri = new_request_uri = tdata->msg->line.req.uri; } /* The target URI must be a SIP/SIPS URL so we can resolve it's address. * Otherwise we're in trouble (i.e. there's no host part in tel: URL). */ pj_bzero(dest_info, sizeof(*dest_info)); if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) { pjsip_uri *uri = (pjsip_uri*) target_uri; const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri); dest_info->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE); pj_strdup(tdata->pool, &dest_info->addr.host, &url->host); dest_info->addr.port = url->port; dest_info->type = pjsip_transport_get_type_from_name(&url->transport_param); } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) { pjsip_uri *uri = (pjsip_uri*) target_uri; const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri); pj_strdup(tdata->pool, &dest_info->addr.host, &url->host); dest_info->addr.port = url->port; dest_info->type = pjsip_transport_get_type_from_name(&url->transport_param); dest_info->flag = pjsip_transport_get_flag_from_type(dest_info->type); } else { pj_assert(!"Unsupported URI scheme!"); PJ_TODO(SUPPORT_REQUEST_ADDR_RESOLUTION_FOR_TEL_URI); return PJSIP_EINVALIDSCHEME; } /* If target URI is different than request URI, replace * request URI add put the original URI in the last Route header. */ if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) { pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool); route->name_addr.uri = pjsip_uri_get_uri(tdata->msg->line.req.uri); if (last_route_hdr) pj_list_insert_after(last_route_hdr, route); else pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route); tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri; } /* Success. */ return PJ_SUCCESS; }/* Transport callback for sending stateless request. * This is one of the most bizzare function in pjsip, so * good luck if you happen to debug this function!! */static void stateless_send_transport_cb( void *token, pjsip_tx_data *tdata, pj_ssize_t sent ){ pjsip_send_state *stateless_data = token; PJ_UNUSED_ARG(tdata); pj_assert(tdata == stateless_data->tdata); for (;;) { pj_status_t status; pj_bool_t cont; pj_sockaddr_t *cur_addr; pjsip_transport_type_e cur_addr_type; int cur_addr_len; pjsip_via_hdr *via; if (sent == -PJ_EPENDING) { /* This is the initial process. * When the process started, this function will be called by * stateless_send_resolver_callback() with sent argument set to * -PJ_EPENDING. */ cont = PJ_TRUE; } else { /* There are two conditions here: * (1) Message is sent (i.e. sent > 0), * (2) Failure (i.e. sent <= 0) */ cont = (sent > 0) ? PJ_FALSE : (stateless_data->cur_addr<stateless_data->addr.count-1); if (stateless_data->app_cb) { (*stateless_data->app_cb)(stateless_data, sent, &cont); } else { /* Doesn't have application callback. * Terminate the process. */ cont = PJ_FALSE; } } /* Finished with this transport. */ if (stateless_data->cur_transport) { pjsip_transport_dec_ref(stateless_data->cur_transport); stateless_data->cur_transport = NULL; } /* Done if application doesn't want to continue. */ if (sent > 0 || !cont) { pjsip_tx_data_dec_ref(tdata); return; } /* Try next address, if any, and only when this is not the * first invocation. */ if (sent != -PJ_EPENDING) { stateless_data->cur_addr++; } /* Have next address? */ if (stateless_data->cur_addr >= stateless_data->addr.count) { /* This only happens when a rather buggy application has * sent 'cont' to PJ_TRUE when the initial value was PJ_FALSE. * In this case just stop the processing; we don't need to * call the callback again as application has been informed * before. */ pjsip_tx_data_dec_ref(tdata); return; } /* Keep current server address information handy. */ cur_addr = &stateless_data->addr.entry[stateless_data->cur_addr].addr; cur_addr_type = stateless_data->addr.entry[stateless_data->cur_addr].type; cur_addr_len = stateless_data->addr.entry[stateless_data->cur_addr].addr_len; /* Acquire transport. */ status = pjsip_endpt_acquire_transport( stateless_data->endpt, cur_addr_type, cur_addr, cur_addr_len, &tdata->tp_sel, &stateless_data->cur_transport); if (status != PJ_SUCCESS) { sent = -status; continue; } /* Modify Via header. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -