diff options
author | Joshua Colp <jcolp@digium.com> | 2012-07-01 17:28:57 +0000 |
---|---|---|
committer | Joshua Colp <jcolp@digium.com> | 2012-07-01 17:28:57 +0000 |
commit | 37256ea45d7a5c088229af496df366dc42005d15 (patch) | |
tree | abf99698af1acb0debf7dcae64d7ca8015710fd1 /channels | |
parent | 628425ba6fdc1ce1aa6f85e33fe83f1e6eeeaa00 (diff) |
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
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 157 |
1 files changed, 154 insertions, 3 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d081c99a9..13a5da3ae 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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) |