📄 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 + -