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

📄 sip_util.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
	via = (pjsip_via_hdr*) pjsip_msg_find_hdr( tdata->msg,
						   PJSIP_H_VIA, NULL);
	if (!via) {
	    /* Shouldn't happen if request was created with PJSIP API! 
	     * But we handle the case anyway for robustness.
	     */
	    pj_assert(!"Via header not found!");
	    via = pjsip_via_hdr_create(tdata->pool);
	    pjsip_msg_insert_first_hdr(tdata->msg, (pjsip_hdr*)via);
	}

	if (via->branch_param.slen == 0) {
	    pj_str_t tmp;
	    via->branch_param.ptr = pj_pool_alloc(tdata->pool,
						  PJSIP_MAX_BRANCH_LEN);
	    via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;
	    pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID,
		      PJSIP_RFC3261_BRANCH_LEN);
	    tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2;
	    *(tmp.ptr-2) = 80; *(tmp.ptr-1) = 106;
	    pj_generate_unique_string(&tmp);
	}

	via->transport = pj_str(stateless_data->cur_transport->type_name);
	via->sent_by = stateless_data->cur_transport->local_name;
	via->rport_param = 0;

	/* Send message using this transport. */
	status = pjsip_transport_send( stateless_data->cur_transport,
				       tdata,
				       cur_addr,
				       cur_addr_len,
				       stateless_data,
				       &stateless_send_transport_cb);
	if (status == PJ_SUCCESS) {
	    /* Recursively call this function. */
	    sent = tdata->buf.cur - tdata->buf.start;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	} else if (status == PJ_EPENDING) {
	    /* This callback will be called later. */
	    return;
	} else {
	    /* Recursively call this function. */
	    sent = -status;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	}
    }

}

/* Resolver callback for sending stateless request. */
static void 
stateless_send_resolver_callback( pj_status_t status,
				  void *token,
				  const struct pjsip_server_addresses *addr)
{
    pjsip_send_state *stateless_data = token;

    /* Fail on server resolution. */
    if (status != PJ_SUCCESS) {
	if (stateless_data->app_cb) {
	    pj_bool_t cont = PJ_FALSE;
	    (*stateless_data->app_cb)(stateless_data, -status, &cont);
	}
	pjsip_tx_data_dec_ref(stateless_data->tdata);
	return;
    }

    /* Copy server addresses */
    pj_memcpy( &stateless_data->addr, addr, sizeof(pjsip_server_addresses));

    /* Process the addresses. */
    stateless_send_transport_cb( stateless_data, stateless_data->tdata,
				 -PJ_EPENDING);
}

/*
 * Send stateless request.
 * The sending process consists of several stages:
 *  - determine which host to contact (#pjsip_get_request_addr).
 *  - resolve the host (#pjsip_endpt_resolve)
 *  - establish transport (#pjsip_endpt_acquire_transport)
 *  - send the message (#pjsip_transport_send)
 */
PJ_DEF(pj_status_t) 
pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt, 
				   pjsip_tx_data *tdata,
				   void *token,
				   void (*cb)(pjsip_send_state*,
					      pj_ssize_t sent,
					      pj_bool_t *cont))
{
    pjsip_host_info dest_info;
    pjsip_send_state *stateless_data;
    pj_status_t status;

    PJ_ASSERT_RETURN(endpt && tdata, PJ_EINVAL);

    /* Get destination name to contact. */
    status = pjsip_process_route_set(tdata, &dest_info);
    if (status != PJ_SUCCESS)
	return status;

    /* Keep stateless data. */
    stateless_data = pj_pool_zalloc(tdata->pool, sizeof(pjsip_send_state));
    stateless_data->token = token;
    stateless_data->endpt = endpt;
    stateless_data->tdata = tdata;
    stateless_data->app_cb = cb;

    /* Resolve destination host.
     * The processing then resumed when the resolving callback is called.
     */
    pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data,
			 &stateless_send_resolver_callback);
    return PJ_SUCCESS;
}

/*
 * Determine which address (and transport) to use to send response message
 * based on the received request. This function follows the specification
 * in section 18.2.2 of RFC 3261 and RFC 3581 for calculating the destination
 * address and transport.
 */
PJ_DEF(pj_status_t) pjsip_get_response_addr( pj_pool_t *pool,
					     pjsip_rx_data *rdata,
					     pjsip_response_addr *res_addr )
{
    pjsip_transport *src_transport = rdata->tp_info.transport;

    /* Check arguments. */
    PJ_ASSERT_RETURN(pool && rdata && res_addr, PJ_EINVAL);

    /* rdata must be a request message! */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJ_EINVAL);

    /* All requests must have "received" parameter.
     * This must always be done in transport layer.
     */
    pj_assert(rdata->msg_info.via->recvd_param.slen != 0);

    /* Do the calculation based on RFC 3261 Section 18.2.2 and RFC 3581 */

    if (PJSIP_TRANSPORT_IS_RELIABLE(src_transport)) {
	/* For reliable protocol such as TCP or SCTP, or TLS over those, the
	 * response MUST be sent using the existing connection to the source
	 * of the original request that created the transaction, if that 
	 * connection is still open. 
	 * If that connection is no longer open, the server SHOULD open a 
	 * connection to the IP address in the received parameter, if present,
	 * using the port in the sent-by value, or the default port for that 
	 * transport, if no port is specified. 
	 * If that connection attempt fails, the server SHOULD use the 
	 * procedures in [4] for servers in order to determine the IP address
	 * and port to open the connection and send the response to.
	 */
	res_addr->transport = rdata->tp_info.transport;
	pj_memcpy(&res_addr->addr, &rdata->pkt_info.src_addr,
		  rdata->pkt_info.src_addr_len);
	res_addr->addr_len = rdata->pkt_info.src_addr_len;
	res_addr->dst_host.type = src_transport->key.type;
	res_addr->dst_host.flag = src_transport->flag;
	pj_strdup( pool, &res_addr->dst_host.addr.host, 
		   &rdata->msg_info.via->recvd_param);
	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
	if (res_addr->dst_host.addr.port == 0) {
	    res_addr->dst_host.addr.port = 
		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
	}

    } else if (rdata->msg_info.via->maddr_param.slen) {
	/* Otherwise, if the Via header field value contains a maddr parameter,
	 * the response MUST be forwarded to the address listed there, using 
	 * the port indicated in sent-by, or port 5060 if none is present. 
	 * If the address is a multicast address, the response SHOULD be sent 
	 * using the TTL indicated in the ttl parameter, or with a TTL of 1 if
	 * that parameter is not present. 
	 */
	res_addr->transport = NULL;
	res_addr->dst_host.type = src_transport->key.type;
	res_addr->dst_host.flag = src_transport->flag;
	pj_strdup( pool, &res_addr->dst_host.addr.host, 
		   &rdata->msg_info.via->maddr_param);
	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
	if (res_addr->dst_host.addr.port == 0)
	    res_addr->dst_host.addr.port = 5060;

    } else if (rdata->msg_info.via->rport_param >= 0) {
	/* There is both a "received" parameter and an "rport" parameter, 
	 * the response MUST be sent to the IP address listed in the "received"
	 * parameter, and the port in the "rport" parameter. 
	 * The response MUST be sent from the same address and port that the 
	 * corresponding request was received on.
	 */
	res_addr->transport = rdata->tp_info.transport;
	pj_memcpy(&res_addr->addr, &rdata->pkt_info.src_addr,
		  rdata->pkt_info.src_addr_len);
	res_addr->addr_len = rdata->pkt_info.src_addr_len;
	res_addr->dst_host.type = src_transport->key.type;
	res_addr->dst_host.flag = src_transport->flag;
	pj_strdup( pool, &res_addr->dst_host.addr.host, 
		   &rdata->msg_info.via->recvd_param);
	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
	if (res_addr->dst_host.addr.port == 0) {
	    res_addr->dst_host.addr.port = 
		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
	}

    } else {
	res_addr->transport = NULL;
	res_addr->dst_host.type = src_transport->key.type;
	res_addr->dst_host.flag = src_transport->flag;
	pj_strdup( pool, &res_addr->dst_host.addr.host, 
		   &rdata->msg_info.via->recvd_param);
	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
	if (res_addr->dst_host.addr.port == 0) {
	    res_addr->dst_host.addr.port = 
		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
	}
    }

    return PJ_SUCCESS;
}

/*
 * Callback called by transport during send_response.
 */
static void send_response_transport_cb(void *token, pjsip_tx_data *tdata,
				       pj_ssize_t sent)
{
    pjsip_send_state *send_state = token;
    pj_bool_t cont = PJ_FALSE;

    /* Call callback, if any. */
    if (send_state->app_cb)
	(*send_state->app_cb)(send_state, sent, &cont);

    /* Decrement transport reference counter. */
    pjsip_transport_dec_ref(send_state->cur_transport);

    /* Decrement transmit data ref counter. */
    pjsip_tx_data_dec_ref(tdata);
}

/*
 * Resolver calback during send_response.
 */
static void send_response_resolver_cb( pj_status_t status, void *token,
				       const pjsip_server_addresses *addr )
{
    pjsip_send_state *send_state = token;

    if (status != PJ_SUCCESS) {
	if (send_state->app_cb) {
	    pj_bool_t cont = PJ_FALSE;
	    (*send_state->app_cb)(send_state, -status, &cont);
	}
	pjsip_tx_data_dec_ref(send_state->tdata);
	return;
    }

    /* Only handle the first address resolved. */

    /* Acquire transport. */
    status = pjsip_endpt_acquire_transport( send_state->endpt, 
					    addr->entry[0].type,
					    &addr->entry[0].addr,
					    addr->entry[0].addr_len,
					    &send_state->tdata->tp_sel,
					    &send_state->cur_transport);
    if (status != PJ_SUCCESS) {
	if (send_state->app_cb) {
	    pj_bool_t cont = PJ_FALSE;
	    (*send_state->app_cb)(send_state, -status, &cont);
	}
	pjsip_tx_data_dec_ref(send_state->tdata);
	return;
    }

    /* Update address in send_state. */
    send_state->addr = *addr;

    /* Send response using the transoprt. */
    status = pjsip_transport_send( send_state->cur_transport, 
				   send_state->tdata,
				   &addr->entry[0].addr,
				   addr->entry[0].addr_len,
				   send_state,
				   &send_response_transport_cb);
    if (status == PJ_SUCCESS) {
	pj_ssize_t sent = send_state->tdata->buf.cur - 
			  send_state->tdata->buf.start;
	send_response_transport_cb(send_state, send_state->tdata, sent);

    } else if (status == PJ_EPENDING) {
	/* Transport callback will be called later. */
    } else {
	send_response_transport_cb(send_state, send_state->tdata, -status);
    }
}

/*
 * Send response.
 */
PJ_DEF(pj_status_t) pjsip_endpt_send_response( pjsip_endpoint *endpt,
					       pjsip_response_addr *res_addr,
					       pjsip_tx_data *tdata,
					       void *token,
					       void (*cb)(pjsip_send_state*,
							  pj_ssize_t sent,
							  pj_bool_t *cont))
{
    /* Determine which transports and addresses to send the response,
     * based on Section 18.2.2 of RFC 3261.
     */
    pjsip_send_state *send_state;
    pj_status_t status;

    /* Create structure to keep the sending state. */
    send_state = pj_pool_zalloc(tdata->pool, sizeof(pjsip_send_state));
    send_state->endpt = endpt;
    send_state->tdata = tdata;
    send_state->token = token;
    send_state->app_cb = cb;

    if (res_addr->transport != NULL) {
	send_state->cur_transport = res_addr->transport;
	pjsip_transport_add_ref(send_state->cur_transport);

	status = pjsip_transport_send( send_state->cur_transport, tdata, 
				       &res_addr->addr,
				       res_addr->addr_len,
				       send_state,
				       &send_response_transport_cb );
	if (status == PJ_SUCCESS) {
	    pj_ssize_t sent = tdata->buf.cur - tdata->buf.start;
	    send_response_transport_cb(send_state, tdata, sent);
	    return PJ_SUCCESS;
	} else if (status == PJ_EPENDING) {
	    /* Callback will be called later. */
	    return PJ_SUCCESS;
	} else {
	    pjsip_transport_dec_ref(send_state->cur_transport);
	    return status;
	}
    } else {
	pjsip_endpt_resolve(endpt, tdata->pool, &res_addr->dst_host, 
			    send_state, &send_response_resolver_cb);
	return PJ_SUCCESS;
    }
}

/*
 * Send response combo
 */
PJ_DEF(pj_status_t) pjsip_endpt_send_response2( pjsip_endpoint *endpt,
					        pjsip_rx_data *rdata,
					        pjsip_tx_data *tdata,
						void *token,
						void (*cb)(pjsip_send_state*,
							   pj_ssize_t sent,
							   pj_bool_t *cont))
{
    pjsip_response_addr res_addr;
    pj_status_t status;

    status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	return PJ_SUCCESS;
    }

    status = pjsip_endpt_send_response(endpt, &res_addr, tdata, token, cb);
    return status;
}


/*
 * Send response
 */
PJ_DEF(pj_status_t) pjsip_endpt_respond_stateless( pjsip_endpoint *endpt,
						   pjsip_rx_data *rdata,
						   int st_code,
						   const pj_str_t *st_text,
						   const pjsip_hdr *hdr_list,
						   const pjsip_msg_body *body)
{
    pj_status_t status;
    pjsip_response_addr res_addr;
    pjsip_tx_data *tdata;

    /* Verify arguments. */
    PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that no UAS transaction has been created for this request. 
     * If UAS transaction has been created for this request, application
     * MUST send the response statefully using that transaction.
     */
    PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata)==NULL, PJ_EINVALIDOP);

    /* Create response message */
    status = pjsip_endpt_create_response( endpt, rdata, st_code, st_text, 
					  &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Add the message headers, if any */
    if (hdr_list) {
	const pjsip_hdr *hdr = hdr_list->next;
	while (hdr != hdr_list) {
	    pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_clone(tdata->pool, hdr) );
	    hdr = hdr->next;
	}
    }

    /* Add the message body, if any. */
    if (body) {
	tdata->msg->body = pjsip_msg_body_clone( tdata->pool, body );
	if (tdata->msg->body == NULL) {
	    pjsip_tx_data_dec_ref(tdata);
	    return status;
	}
    }

    /* Get where to send request. */
    status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr );
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	return status;
    }

    /* Send! */
    status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL );

    return status;
}


/*
 * Get the event string from the event ID.
 */
PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)
{
    return event_str[e];
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -