Пример #1
0
/*! \brief Function which adds ICE attributes to a media stream */
static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
{
	struct ast_rtp_engine_ice *ice;
	struct ao2_container *candidates;
	const char *username, *password;
	pj_str_t stmp;
	pjmedia_sdp_attr *attr;
	struct ao2_iterator it_candidates;
	struct ast_rtp_engine_ice_candidate *candidate;

	if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) ||
		!(candidates = ice->get_local_candidates(session_media->rtp))) {
		return;
	}

	if ((username = ice->get_ufrag(session_media->rtp))) {
		attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
		media->attr[media->attr_count++] = attr;
	}

	if ((password = ice->get_password(session_media->rtp))) {
		attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
		media->attr[media->attr_count++] = attr;
	}

	it_candidates = ao2_iterator_init(candidates, 0);
	for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
		struct ast_str *attr_candidate = ast_str_create(128);

		ast_str_set(&attr_candidate, -1, "%s %u %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
					candidate->priority, ast_sockaddr_stringify_host(&candidate->address));
		ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));

		switch (candidate->type) {
			case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
				ast_str_append(&attr_candidate, -1, "host");
				break;
			case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
				ast_str_append(&attr_candidate, -1, "srflx");
				break;
			case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
				ast_str_append(&attr_candidate, -1, "relay");
				break;
		}

		if (!ast_sockaddr_isnull(&candidate->relay_address)) {
			ast_str_append(&attr_candidate, -1, " raddr %s rport ", ast_sockaddr_stringify_host(&candidate->relay_address));
			ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
		}

		attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
		media->attr[media->attr_count++] = attr;

		ast_free(attr_candidate);
	}

	ao2_iterator_destroy(&it_candidates);
}
Пример #2
0
/*!
 * \brief Pass WebSocket data into pjsip transport manager.
 */
static int transport_read(void *data)
{
	struct transport_read_data *read_data = data;
	struct ws_transport *newtransport = read_data->transport;
	struct ast_websocket *session = newtransport->ws_session;

	pjsip_rx_data *rdata = &newtransport->rdata;
	int recvd;
	pj_str_t buf;
	int pjsip_pkt_len;

	pj_gettimeofday(&rdata->pkt_info.timestamp);

	pjsip_pkt_len = PJSIP_MAX_PKT_LEN < read_data->payload_len ? PJSIP_MAX_PKT_LEN : read_data->payload_len;
	pj_memcpy(rdata->pkt_info.packet, read_data->payload, pjsip_pkt_len);
	rdata->pkt_info.len = pjsip_pkt_len;
	rdata->pkt_info.zero = 0;

	pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(session))), &rdata->pkt_info.src_addr);
	rdata->pkt_info.src_addr.addr.sa_family = pj_AF_INET();

	rdata->pkt_info.src_addr_len = sizeof(rdata->pkt_info.src_addr);

	pj_ansi_strcpy(rdata->pkt_info.src_name, ast_sockaddr_stringify_host(ast_websocket_remote_address(session)));
	rdata->pkt_info.src_port = ast_sockaddr_port(ast_websocket_remote_address(session));

	recvd = pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, rdata);

	pj_pool_reset(rdata->tp_info.pool);

	return (read_data->payload_len == recvd) ? 0 : -1;
}
Пример #3
0
static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
{
	RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
	struct request_transport_details details = { 0, };
	pjsip_via_hdr *via = NULL;
	struct ast_sockaddr addr = { { 0, } };
	pjsip_sip_uri *uri = NULL;
	RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);

	/* If a transport selector is in use we know the transport or factory, so explicitly find it */
	if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
		details.transport = tdata->tp_sel.u.transport;
	} else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
		details.factory = tdata->tp_sel.u.listener;
	} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
		/* Connectionless uses the same transport for all requests */
		details.type = AST_TRANSPORT_UDP;
		details.transport = tdata->tp_info.transport;
	} else {
		if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
			details.type = AST_TRANSPORT_TCP;
		} else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
			details.type = AST_TRANSPORT_TLS;
		} else {
			/* Unknown transport type, we can't map and thus can't apply NAT changes */
			return PJ_SUCCESS;
		}

		if ((uri = nat_get_contact_sip_uri(tdata))) {
			details.local_address = uri->host;
			details.local_port = uri->port;
		} else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
			(via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
			details.local_address = via->sent_by.host;
			details.local_port = via->sent_by.port;
		} else {
			return PJ_SUCCESS;
		}

		if (!details.local_port) {
			details.local_port = (details.type == AST_TRANSPORT_TLS) ? 5061 : 5060;
		}
	}

	if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
		!(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
		ast_sockaddr_isnull(&transport->external_address)) {
		return PJ_SUCCESS;
	}

	ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
	ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);

	/* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
	if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
		return PJ_SUCCESS;
	}

	/* Update the contact header with the external address */
	if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
		pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
		if (transport->external_signaling_port) {
			uri->port = transport->external_signaling_port;
			ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
		}
	}

	/* Update the via header if relevant */
	if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
		pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address));
		if (transport->external_signaling_port) {
			via->sent_by.port = transport->external_signaling_port;
		}
	}

	/* Invoke any additional hooks that may be registered */
	if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
		struct nat_hook_details hook_details = {
			.tdata = tdata,
			.transport = transport,
		};
		ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
	}

	return PJ_SUCCESS;
}