⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sip_util.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -