Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.

Review: https://reviewboard.asterisk.org/r/1891/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369517 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Joshua Colp
2012-07-01 17:28:57 +00:00
parent 628425ba6f
commit 37256ea45d
1947 changed files with 1120896 additions and 37 deletions

View File

@@ -1343,10 +1343,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
static int process_sdp_o(const char *o, struct sip_pvt *p);
static int process_sdp_c(const char *c, struct ast_sockaddr *addr);
static int process_sdp_a_sendonly(const char *a, int *sendonly);
static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance);
static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec);
static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec);
static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec);
static int process_sdp_a_image(const char *a, struct sip_pvt *p);
static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
static void start_ice(struct ast_rtp_instance *instance);
static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
struct ast_str **m_buf, struct ast_str **a_buf,
int debug, int *min_packet_size);
@@ -9273,6 +9276,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
processed = TRUE;
else if (process_sdp_a_image(value, p))
processed = TRUE;
if (process_sdp_a_ice(value, p, p->rtp)) {
processed = TRUE;
}
if (process_sdp_a_ice(value, p, p->vrtp)) {
processed = TRUE;
}
if (process_sdp_a_ice(value, p, p->trtp)) {
processed = TRUE;
}
break;
}
@@ -9584,7 +9598,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
case 'a':
/* Audio specific scanning */
if (audio) {
if (process_sdp_a_sendonly(value, &sendonly)) {
if (process_sdp_a_ice(value, p, p->rtp)) {
processed = TRUE;
} else if (process_sdp_a_sendonly(value, &sendonly)) {
processed = TRUE;
} else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) {
processed_crypto = TRUE;
@@ -9595,7 +9611,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
}
/* Video specific scanning */
else if (video) {
if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
if (process_sdp_a_ice(value, p, p->vrtp)) {
processed = TRUE;
} else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
processed_crypto = TRUE;
processed = TRUE;
} else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec)) {
@@ -9604,7 +9622,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
}
/* Text (T.140) specific scanning */
else if (text) {
if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) {
if (process_sdp_a_ice(value, p, p->trtp)) {
processed = TRUE;
} if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec)) {
processed = TRUE;
} else if (!processed_crypto && process_crypto(p, p->trtp, &p->tsrtp, value)) {
processed_crypto = TRUE;
@@ -9734,6 +9754,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* Setup audio address and port */
if (p->rtp) {
if (portno > 0) {
start_ice(p->rtp);
ast_sockaddr_set_port(sa, portno);
ast_rtp_instance_set_remote_address(p->rtp, sa);
if (debug) {
@@ -9781,6 +9802,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* Setup video address and port */
if (p->vrtp) {
if (vportno > 0) {
start_ice(p->vrtp);
ast_sockaddr_set_port(vsa, vportno);
ast_rtp_instance_set_remote_address(p->vrtp, vsa);
if (debug) {
@@ -9798,6 +9820,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* Setup text address and port */
if (p->trtp) {
if (tportno > 0) {
start_ice(p->trtp);
ast_sockaddr_set_port(tsa, tportno);
ast_rtp_instance_set_remote_address(p->trtp, tsa);
if (debug) {
@@ -10062,6 +10085,61 @@ static int process_sdp_a_sendonly(const char *a, int *sendonly)
return found;
}
static int process_sdp_a_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance)
{
struct ast_rtp_engine_ice *ice;
int found = FALSE;
char ufrag[256], pwd[256], foundation[32], transport[4], address[46], cand_type[6], relay_address[46] = "";
struct ast_rtp_engine_ice_candidate candidate = { 0, };
int port, relay_port = 0;
if (!instance || !(ice = ast_rtp_instance_get_ice(instance))) {
return found;
}
if (sscanf(a, "ice-ufrag: %255s", ufrag) == 1) {
ice->set_authentication(instance, ufrag, NULL);
found = TRUE;
} else if (sscanf(a, "ice-pwd: %255s", pwd) == 1) {
ice->set_authentication(instance, NULL, pwd);
found = TRUE;
} else if (sscanf(a, "candidate: %31s %30u %3s %30u %23s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, &candidate.priority,
address, &port, cand_type, relay_address, &relay_port) >= 7) {
candidate.foundation = foundation;
candidate.transport = transport;
ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
ast_sockaddr_set_port(&candidate.address, port);
if (!strcasecmp(cand_type, "host")) {
candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
} else if (!strcasecmp(cand_type, "srflx")) {
candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
} else if (!strcasecmp(cand_type, "relay")) {
candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
} else {
return found;
}
if (!ast_strlen_zero(relay_address)) {
ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
}
if (relay_port) {
ast_sockaddr_set_port(&candidate.relay_address, relay_port);
}
ice->add_remote_candidate(instance, &candidate);
found = TRUE;
} else if (!strcasecmp(a, "ice-lite")) {
ice->ice_lite(instance);
found = TRUE;
}
return found;
}
static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec)
{
int found = FALSE;
@@ -11568,6 +11646,67 @@ static int add_vidupdate(struct sip_request *req)
return 0;
}
/*! \brief Add ICE attributes to SDP */
static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf)
{
struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(instance);
const char *username, *password;
struct ao2_container *candidates;
struct ao2_iterator i;
struct ast_rtp_engine_ice_candidate *candidate;
/* If no ICE support is present we can't very well add the attributes */
if (!ice || !(candidates = ice->get_local_candidates(instance))) {
return;
}
if ((username = ice->get_ufrag(instance))) {
ast_str_append(a_buf, 0, "a=ice-ufrag:%s\r\n", username);
}
if ((password = ice->get_password(instance))) {
ast_str_append(a_buf, 0, "a=ice-pwd:%s\r\n", password);
}
i = ao2_iterator_init(candidates, 0);
while ((candidate = ao2_iterator_next(&i))) {
ast_str_append(a_buf, 0, "a=candidate:%s %d %s %d ", candidate->foundation, candidate->id, candidate->transport, candidate->priority);
ast_str_append(a_buf, 0, "%s ", ast_sockaddr_stringify_host(&candidate->address));
ast_str_append(a_buf, 0, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
ast_str_append(a_buf, 0, "host");
} else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
ast_str_append(a_buf, 0, "srflx");
} else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
ast_str_append(a_buf, 0, "relay");
}
if (!ast_sockaddr_isnull(&candidate->relay_address)) {
ast_str_append(a_buf, 0, " raddr %s ", ast_sockaddr_stringify_host(&candidate->relay_address));
ast_str_append(a_buf, 0, "rport %s", ast_sockaddr_stringify_port(&candidate->relay_address));
}
ast_str_append(a_buf, 0, "\r\n");
}
ao2_iterator_destroy(&i);
ao2_ref(candidates, -1);
}
/*! \brief Start ICE negotiation on an RTP instance */
static void start_ice(struct ast_rtp_instance *instance)
{
struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(instance);
if (!ice) {
return;
}
ice->start(instance);
}
/*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
static void add_codec_to_sdp(const struct sip_pvt *p,
struct ast_format *format,
@@ -12038,6 +12177,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
if (debug) {
ast_verbose("Video is at %s\n", ast_sockaddr_stringify(&vdest));
}
if (!doing_directmedia) {
add_ice_to_sdp(p->vrtp, &a_video);
}
}
/* Ok, we need text. Let's add what we need for text and set codecs.
@@ -12051,6 +12194,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
if (debug) { /* XXX should I use tdest below ? */
ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr));
}
if (!doing_directmedia) {
add_ice_to_sdp(p->trtp, &a_text);
}
}
/* Start building generic SDP headers */
@@ -12145,6 +12292,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
if (min_text_packet_size)
ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
if (!doing_directmedia) {
add_ice_to_sdp(p->rtp, &a_audio);
}
if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)