summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2013-06-22 14:03:22 +0000
committerJoshua Colp <jcolp@digium.com>2013-06-22 14:03:22 +0000
commit77002bc377f19ea11e60732c486b6ef371688773 (patch)
treec19fd245c519c6d7905403849a7af9c7e4a4be3e /channels
parentea03516cb5426915d183526335d3a7d662ea29dc (diff)
Merge in current pimp_my_sip work, including:
1. Security events 2. Websocket support 3. Diversion header + redirecting support 4. An anonymous endpoint identifier 5. Inbound extension state subscription support 6. PIDF notify generation 7. One touch recording support (special thanks Sean Bright!) 8. Blind and attended transfer support 9. Automatic inbound registration expiration 10. SRTP support 11. Media offer control dialplan function 12. Connected line support 13. SendText() support 14. Qualify support 15. Inband DTMF detection 16. Call and pickup groups 17. Messaging support Thanks everyone! Side note: I'm reminded of the song "How Far We've Come" by Matchbox Twenty. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392565 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_gulp.c461
-rw-r--r--channels/chan_sip.c136
-rw-r--r--channels/sip/include/sdp_crypto.h85
-rw-r--r--channels/sip/include/sip.h6
-rw-r--r--channels/sip/include/srtp.h59
-rw-r--r--channels/sip/sdp_crypto.c318
-rw-r--r--channels/sip/srtp.c55
7 files changed, 482 insertions, 638 deletions
diff --git a/channels/chan_gulp.c b/channels/chan_gulp.c
index 9e939a0f4..6a80651cf 100644
--- a/channels/chan_gulp.c
+++ b/channels/chan_gulp.c
@@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/musiconhold.h"
#include "asterisk/causes.h"
#include "asterisk/taskprocessor.h"
+#include "asterisk/dsp.h"
#include "asterisk/stasis_endpoints.h"
#include "asterisk/stasis_channels.h"
@@ -79,6 +80,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
</description>
</function>
+ <function name="GULP_MEDIA_OFFER" language="en_US">
+ <synopsis>
+ Media and codec offerings to be set on an outbound SIP channel prior to dialing.
+ </synopsis>
+ <syntax>
+ <parameter name="media" required="true">
+ <para>types of media offered</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Returns the codecs offered based upon the media choice</para>
+ </description>
+ </function>
***/
static const char desc[] = "Gulp SIP Channel";
@@ -128,6 +142,7 @@ static int gulp_answer(struct ast_channel *ast);
static struct ast_frame *gulp_read(struct ast_channel *ast);
static int gulp_write(struct ast_channel *ast, struct ast_frame *f);
static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int gulp_transfer(struct ast_channel *ast, const char *target);
static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int gulp_devicestate(const char *data);
@@ -147,6 +162,7 @@ static struct ast_channel_tech gulp_tech = {
.write_video = gulp_write,
.exception = gulp_read,
.indicate = gulp_indicate,
+ .transfer = gulp_transfer,
.fixup = gulp_fixup,
.devicestate = gulp_devicestate,
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
@@ -255,6 +271,105 @@ static struct ast_custom_function gulp_dial_contacts_function = {
.read = gulp_dial_contacts,
};
+static int media_offer_read_av(struct ast_sip_session *session, char *buf,
+ size_t len, enum ast_format_type media_type)
+{
+ int i, size = 0;
+ struct ast_format fmt;
+ const char *name;
+
+ for (i = 0; ast_codec_pref_index(&session->override_prefs, i, &fmt); ++i) {
+ if (AST_FORMAT_GET_TYPE(fmt.id) != media_type) {
+ continue;
+ }
+
+ name = ast_getformatname(&fmt);
+
+ if (ast_strlen_zero(name)) {
+ ast_log(LOG_WARNING, "GULP_MEDIA_OFFER unrecognized format %s\n", name);
+ continue;
+ }
+
+ /* add one since we'll include a comma */
+ size = strlen(name) + 1;
+ len -= size;
+ if ((len) < 0) {
+ break;
+ }
+
+ /* no reason to use strncat here since we have already ensured buf has
+ enough space, so strcat can be safely used */
+ strcat(buf, name);
+ strcat(buf, ",");
+ }
+
+ if (size) {
+ /* remove the extra comma */
+ buf[strlen(buf) - 1] = '\0';
+ }
+ return 0;
+}
+
+struct media_offer_data {
+ struct ast_sip_session *session;
+ enum ast_format_type media_type;
+ const char *value;
+};
+
+static int media_offer_write_av(void *obj)
+{
+ struct media_offer_data *data = obj;
+ int i;
+ struct ast_format fmt;
+ /* remove all of the given media type first */
+ for (i = 0; ast_codec_pref_index(&data->session->override_prefs, i, &fmt); ++i) {
+ if (AST_FORMAT_GET_TYPE(fmt.id) == data->media_type) {
+ ast_codec_pref_remove(&data->session->override_prefs, &fmt);
+ }
+ }
+ ast_format_cap_remove_bytype(data->session->req_caps, data->media_type);
+ ast_parse_allow_disallow(&data->session->override_prefs, data->session->req_caps, data->value, 1);
+
+ return 0;
+}
+
+static int media_offer_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ if (!strcmp(data, "audio")) {
+ return media_offer_read_av(pvt->session, buf, len, AST_FORMAT_TYPE_AUDIO);
+ } else if (!strcmp(data, "video")) {
+ return media_offer_read_av(pvt->session, buf, len, AST_FORMAT_TYPE_VIDEO);
+ }
+
+ return 0;
+}
+
+static int media_offer_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ struct media_offer_data mdata = {
+ .session = pvt->session,
+ .value = value
+ };
+
+ if (!strcmp(data, "audio")) {
+ mdata.media_type = AST_FORMAT_TYPE_AUDIO;
+ } else if (!strcmp(data, "video")) {
+ mdata.media_type = AST_FORMAT_TYPE_VIDEO;
+ }
+
+ return ast_sip_push_task_synchronous(pvt->session->serializer, media_offer_write_av, &mdata);
+}
+
+static struct ast_custom_function media_offer_function = {
+ .name = "GULP_MEDIA_OFFER",
+ .read = media_offer_read,
+ .write = media_offer_write
+};
+
/*! \brief Function called by RTP engine to get local audio RTP peer */
static enum ast_rtp_glue_result gulp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
{
@@ -402,7 +517,11 @@ static int gulp_set_rtp_peer(struct ast_channel *chan,
if (changed) {
ao2_ref(session, +1);
- ast_sip_push_task(session->serializer, send_direct_media_request, session);
+
+
+ if (ast_sip_push_task(session->serializer, send_direct_media_request, session)) {
+ ao2_cleanup(session);
+ }
}
return 0;
@@ -467,6 +586,12 @@ static struct ast_channel *gulp_new(struct ast_sip_session *session, int state,
ast_channel_exten_set(chan, S_OR(exten, "s"));
ast_channel_priority_set(chan, 1);
+ ast_channel_callgroup_set(chan, session->endpoint->callgroup);
+ ast_channel_pickupgroup_set(chan, session->endpoint->pickupgroup);
+
+ ast_channel_named_callgroups_set(chan, session->endpoint->named_callgroups);
+ ast_channel_named_pickupgroups_set(chan, session->endpoint->named_pickupgroups);
+
ast_endpoint_add_channel(session->endpoint->persistent, chan);
return chan;
@@ -513,6 +638,7 @@ static int gulp_answer(struct ast_channel *ast)
static struct ast_frame *gulp_read(struct ast_channel *ast)
{
struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
struct ast_frame *f;
struct ast_sip_session_media *media = NULL;
int rtcp = 0;
@@ -539,14 +665,27 @@ static struct ast_frame *gulp_read(struct ast_channel *ast)
return &ast_null_frame;
}
- f = ast_rtp_instance_read(media->rtp, rtcp);
+ if (!(f = ast_rtp_instance_read(media->rtp, rtcp))) {
+ return f;
+ }
+
+ if (f->frametype != AST_FRAME_VOICE) {
+ return f;
+ }
- if (f && f->frametype == AST_FRAME_VOICE) {
- if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
- ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
- ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format);
- ast_set_read_format(ast, ast_channel_readformat(ast));
- ast_set_write_format(ast, ast_channel_writeformat(ast));
+ if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
+ ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+ ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format);
+ ast_set_read_format(ast, ast_channel_readformat(ast));
+ ast_set_write_format(ast, ast_channel_writeformat(ast));
+ }
+
+ if (session->dsp) {
+ f = ast_dsp_process(ast, session->dsp, f);
+
+ if (f && (f->frametype == AST_FRAME_DTMF)) {
+ ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer,
+ ast_channel_name(ast));
}
}
@@ -769,7 +908,7 @@ static int transmit_info_with_vidupdate(void *data)
.body_text = xml
};
- struct ast_sip_session *session = data;
+ RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
struct pjsip_tx_data *tdata;
if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
@@ -785,6 +924,40 @@ static int transmit_info_with_vidupdate(void *data)
return 0;
}
+/*! \brief Update connected line information */
+static int update_connected_line_information(void *data)
+{
+ RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
+
+ if ((ast_channel_state(session->channel) != AST_STATE_UP) && (session->inv_session->role == PJSIP_UAS_ROLE)) {
+ int response_code = 0;
+
+ if (ast_channel_state(session->channel) == AST_STATE_RING) {
+ response_code = !session->endpoint->inband_progress ? 180 : 183;
+ } else if (ast_channel_state(session->channel) == AST_STATE_RINGING) {
+ response_code = 183;
+ }
+
+ if (response_code) {
+ struct pjsip_tx_data *packet = NULL;
+
+ if (pjsip_inv_answer(session->inv_session, response_code, NULL, NULL, &packet) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, packet);
+ }
+ }
+ } else {
+ enum ast_sip_session_refresh_method method = session->endpoint->connected_line_method;
+
+ if (session->inv_session->invite_tsx && (session->inv_session->options & PJSIP_INV_SUPPORT_UPDATE)) {
+ method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
+ }
+
+ ast_sip_session_refresh(session, NULL, NULL, method, 0);
+ }
+
+ return 0;
+}
+
/*! \brief Function called by core to ask the channel to indicate some sort of condition */
static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
{
@@ -797,7 +970,12 @@ static int gulp_indicate(struct ast_channel *ast, int condition, const void *dat
switch (condition) {
case AST_CONTROL_RINGING:
if (ast_channel_state(ast) == AST_STATE_RING) {
- response_code = 180;
+ if (session->endpoint->inband_progress) {
+ response_code = 183;
+ res = -1;
+ } else {
+ response_code = 180;
+ }
} else {
res = -1;
}
@@ -841,9 +1019,20 @@ static int gulp_indicate(struct ast_channel *ast, int condition, const void *dat
case AST_CONTROL_VIDUPDATE:
media = pvt->media[SIP_MEDIA_VIDEO];
if (media && media->rtp) {
- ast_sip_push_task(session->serializer, transmit_info_with_vidupdate, session);
- } else
+ ao2_ref(session, +1);
+
+ if (ast_sip_push_task(session->serializer, transmit_info_with_vidupdate, session)) {
+ ao2_cleanup(session);
+ }
+ } else {
res = -1;
+ }
+ break;
+ case AST_CONTROL_CONNECTED_LINE:
+ ao2_ref(session, +1);
+ if (ast_sip_push_task(session->serializer, update_connected_line_information, session)) {
+ ao2_cleanup(session);
+ }
break;
case AST_CONTROL_UPDATE_RTP_PEER:
case AST_CONTROL_PVT_CAUSE_CODE:
@@ -858,6 +1047,13 @@ static int gulp_indicate(struct ast_channel *ast, int condition, const void *dat
break;
case AST_CONTROL_SRCCHANGE:
break;
+ case AST_CONTROL_REDIRECTING:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 181;
+ } else {
+ res = -1;
+ }
+ break;
case -1:
res = -1;
break;
@@ -867,16 +1063,12 @@ static int gulp_indicate(struct ast_channel *ast, int condition, const void *dat
break;
}
- if (!res && response_code) {
+ if (response_code) {
struct indicate_data *ind_data = indicate_data_alloc(session, condition, response_code, data, datalen);
- if (ind_data) {
- res = ast_sip_push_task(session->serializer, indicate, ind_data);
- if (res) {
- ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
- response_code, ast_sorcery_object_get_id(session->endpoint));
- ao2_cleanup(ind_data);
- }
- } else {
+ if (!ind_data || ast_sip_push_task(session->serializer, indicate, ind_data)) {
+ ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
+ response_code, ast_sorcery_object_get_id(session->endpoint));
+ ao2_cleanup(ind_data);
res = -1;
}
}
@@ -884,6 +1076,130 @@ static int gulp_indicate(struct ast_channel *ast, int condition, const void *dat
return res;
}
+struct transfer_data {
+ struct ast_sip_session *session;
+ char *target;
+};
+
+static void transfer_data_destroy(void *obj)
+{
+ struct transfer_data *trnf_data = obj;
+
+ ast_free(trnf_data->target);
+ ao2_cleanup(trnf_data->session);
+}
+
+static struct transfer_data *transfer_data_alloc(struct ast_sip_session *session, const char *target)
+{
+ struct transfer_data *trnf_data = ao2_alloc(sizeof(*trnf_data), transfer_data_destroy);
+
+ if (!trnf_data) {
+ return NULL;
+ }
+
+ if (!(trnf_data->target = ast_strdup(target))) {
+ ao2_ref(trnf_data, -1);
+ return NULL;
+ }
+
+ ao2_ref(session, +1);
+ trnf_data->session = session;
+
+ return trnf_data;
+}
+
+static void transfer_redirect(struct ast_sip_session *session, const char *target)
+{
+ pjsip_tx_data *packet;
+ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+ pjsip_contact_hdr *contact;
+ pj_str_t tmp;
+
+ if (pjsip_inv_end_session(session->inv_session, 302, NULL, &packet) != PJ_SUCCESS) {
+ message = AST_TRANSFER_FAILED;
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+
+ return;
+ }
+
+ if (!(contact = pjsip_msg_find_hdr(packet->msg, PJSIP_H_CONTACT, NULL))) {
+ contact = pjsip_contact_hdr_create(packet->pool);
+ }
+
+ pj_strdup2_with_null(packet->pool, &tmp, target);
+ if (!(contact->uri = pjsip_parse_uri(packet->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR))) {
+ message = AST_TRANSFER_FAILED;
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ pjsip_tx_data_dec_ref(packet);
+
+ return;
+ }
+ pjsip_msg_add_hdr(packet->msg, (pjsip_hdr *) contact);
+
+ ast_sip_session_send_response(session, packet);
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+}
+
+static void transfer_refer(struct ast_sip_session *session, const char *target)
+{
+ pjsip_evsub *sub;
+ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+ pj_str_t tmp;
+ pjsip_tx_data *packet;
+
+ if (pjsip_xfer_create_uac(session->inv_session->dlg, NULL, &sub) != PJ_SUCCESS) {
+ message = AST_TRANSFER_FAILED;
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+
+ return;
+ }
+
+ if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
+ message = AST_TRANSFER_FAILED;
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ pjsip_evsub_terminate(sub, PJ_FALSE);
+
+ return;
+ }
+
+ pjsip_xfer_send_request(sub, packet);
+ ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+}
+
+static int transfer(void *data)
+{
+ struct transfer_data *trnf_data = data;
+
+ if (ast_channel_state(trnf_data->session->channel) == AST_STATE_RING) {
+ transfer_redirect(trnf_data->session, trnf_data->target);
+ } else {
+ transfer_refer(trnf_data->session, trnf_data->target);
+ }
+
+ ao2_ref(trnf_data, -1);
+ return 0;
+}
+
+/*! \brief Function called by core for Asterisk initiated transfer */
+static int gulp_transfer(struct ast_channel *chan, const char *target)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ struct ast_sip_session *session = pvt->session;
+ struct transfer_data *trnf_data = transfer_data_alloc(session, target);
+
+ if (!trnf_data) {
+ return -1;
+ }
+
+ if (ast_sip_push_task(session->serializer, transfer, trnf_data)) {
+ ast_log(LOG_WARNING, "Error requesting transfer\n");
+ ao2_cleanup(trnf_data);
+ return -1;
+ }
+
+ return 0;
+}
+
/*! \brief Function called by core to start a DTMF digit */
static int gulp_digit_begin(struct ast_channel *chan, char digit)
{
@@ -1014,18 +1330,18 @@ static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int dura
static int call(void *data)
{
- pjsip_tx_data *packet;
struct ast_sip_session *session = data;
+ pjsip_tx_data *tdata;
+
+ int res = ast_sip_session_create_invite(session, &tdata);
- if (pjsip_inv_invite(session->inv_session, &packet) != PJ_SUCCESS) {
+ if (res) {
ast_queue_hangup(session->channel);
} else {
- ast_sip_session_send_request(session, packet);
+ ast_sip_session_send_request(session, tdata);
}
-
ao2_ref(session, -1);
-
- return 0;
+ return res;
}
/*! \brief Function called by core to actually start calling a remote party */
@@ -1128,7 +1444,8 @@ static int hangup(void *data)
struct ast_sip_session *session = pvt->session;
int cause = h_data->cause;
- if (((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS) && packet) {
+ if (!session->defer_terminate &&
+ ((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS) && packet) {
if (packet->msg->type == PJSIP_RESPONSE_MSG) {
ast_sip_session_send_response(session, packet);
} else {
@@ -1255,9 +1572,66 @@ static struct ast_channel *gulp_request(const char *type, struct ast_format_cap
return session->channel;
}
+struct sendtext_data {
+ struct ast_sip_session *session;
+ char text[0];
+};
+
+static void sendtext_data_destroy(void *obj)
+{
+ struct sendtext_data *data = obj;
+ ao2_ref(data->session, -1);
+}
+
+static struct sendtext_data* sendtext_data_create(struct ast_sip_session *session, const char *text)
+{
+ int size = strlen(text) + 1;
+ struct sendtext_data *data = ao2_alloc(sizeof(*data)+size, sendtext_data_destroy);
+
+ if (!data) {
+ return NULL;
+ }
+
+ data->session = session;
+ ao2_ref(data->session, +1);
+ ast_copy_string(data->text, text, size);
+ return data;
+}
+
+static int sendtext(void *obj)
+{
+ RAII_VAR(struct sendtext_data *, data, obj, ao2_cleanup);
+ pjsip_tx_data *tdata;
+
+ const struct ast_sip_body body = {
+ .type = "text",
+ .subtype = "plain",
+ .body_text = data->text
+ };
+
+ /* NOT ast_strlen_zero, because a zero-length message is specifically
+ * allowed by RFC 3428 (See section 10, Examples) */
+ if (!data->text) {
+ return 0;
+ }
+
+ ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, &tdata);
+ ast_sip_add_body(tdata, &body);
+ ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint);
+
+ return 0;
+}
+
/*! \brief Function called by core to send text on Gulp session */
static int gulp_sendtext(struct ast_channel *ast, const char *text)
{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct sendtext_data *data = sendtext_data_create(pvt->session, text);
+
+ if (!data || ast_sip_push_task(pvt->session->serializer, sendtext, data)) {
+ ao2_ref(data, -1);
+ return -1;
+ }
return 0;
}
@@ -1391,7 +1765,6 @@ static void gulp_session_end(struct ast_sip_session *session)
static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
{
pjsip_tx_data *packet = NULL;
- int res = AST_PBX_FAILED;
if (session->channel) {
return 0;
@@ -1405,6 +1778,14 @@ static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_r
ast_log(LOG_ERROR, "Failed to allocate new GULP channel on incoming SIP INVITE\n");
return -1;
}
+ /* channel gets created on incoming request, but we wait to call start
+ so other supplements have a chance to run */
+ return 0;
+}
+
+static int pbx_start_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ int res;
res = ast_pbx_start(session->channel);
@@ -1429,6 +1810,12 @@ static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_r
return (res == AST_PBX_SUCCESS) ? 0 : -1;
}
+static struct ast_sip_session_supplement pbx_start_supplement = {
+ .method = "INVITE",
+ .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_LAST,
+ .incoming_request = pbx_start_incoming_request,
+};
+
/*! \brief Function called when a response is received on the session */
static void gulp_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
{
@@ -1496,13 +1883,24 @@ static int load_module(void)
goto end;
}
+ if (ast_custom_function_register(&media_offer_function)) {
+ ast_log(LOG_WARNING, "Unable to register GULP_MEDIA_OFFER dialplan function\n");
+ }
+
if (ast_sip_session_register_supplement(&gulp_supplement)) {
ast_log(LOG_ERROR, "Unable to register Gulp supplement\n");
goto end;
}
+ if (ast_sip_session_register_supplement(&pbx_start_supplement)) {
+ ast_log(LOG_ERROR, "Unable to register Gulp pbx start supplement\n");
+ ast_sip_session_unregister_supplement(&gulp_supplement);
+ goto end;
+ }
+
if (ast_sip_session_register_supplement(&gulp_ack_supplement)) {
ast_log(LOG_ERROR, "Unable to register Gulp ACK supplement\n");
+ ast_sip_session_unregister_supplement(&pbx_start_supplement);
ast_sip_session_unregister_supplement(&gulp_supplement);
goto end;
}
@@ -1510,6 +1908,7 @@ static int load_module(void)
return 0;
end:
+ ast_custom_function_unregister(&media_offer_function);
ast_custom_function_unregister(&gulp_dial_contacts_function);
ast_channel_unregister(&gulp_tech);
ast_rtp_glue_unregister(&gulp_rtp_glue);
@@ -1526,7 +1925,11 @@ static int reload(void)
/*! \brief Unload the Gulp channel from Asterisk */
static int unload_module(void)
{
+ ast_custom_function_unregister(&media_offer_function);
+
ast_sip_session_unregister_supplement(&gulp_supplement);
+ ast_sip_session_unregister_supplement(&pbx_start_supplement);
+
ast_custom_function_unregister(&gulp_dial_contacts_function);
ast_channel_unregister(&gulp_tech);
ast_rtp_glue_unregister(&gulp_rtp_glue);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index c207e24fe..689b43a05 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -285,8 +285,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "sip/include/config_parser.h"
#include "sip/include/reqresp_parser.h"
#include "sip/include/sip_utils.h"
-#include "sip/include/srtp.h"
-#include "sip/include/sdp_crypto.h"
+#include "asterisk/sdp_srtp.h"
#include "asterisk/ccss.h"
#include "asterisk/xml.h"
#include "sip/include/dialog.h"
@@ -1490,8 +1489,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
/*------ SRTP Support -------- */
-static int setup_srtp(struct sip_srtp **srtp);
-static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a);
+static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a);
/*------ T38 Support --------- */
static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
@@ -5918,7 +5916,7 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket
}
/*! \brief Initialize DTLS-SRTP support on an RTP instance */
-static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct sip_srtp **srtp)
+static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp)
{
struct ast_rtp_engine_dtls *dtls;
@@ -5943,7 +5941,7 @@ static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_
return -1;
}
- if (!(*srtp = sip_srtp_alloc())) {
+ if (!(*srtp = ast_sdp_srtp_alloc())) {
ast_log(LOG_ERROR, "Failed to create required SRTP structure on RTP instance '%p'\n",
rtp);
return -1;
@@ -6418,17 +6416,17 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout)
ast_clear_flag(&p->flags[0], SIP_REINVITE);
}
- if (p->rtp && !p->srtp && setup_srtp(&p->srtp) < 0) {
+ if (p->rtp && !p->srtp && !(p->srtp = ast_sdp_srtp_alloc())) {
ast_log(LOG_WARNING, "SRTP audio setup failed\n");
return -1;
}
- if (p->vrtp && !p->vsrtp && setup_srtp(&p->vsrtp) < 0) {
+ if (p->vrtp && !p->vsrtp && !(p->vsrtp = ast_sdp_srtp_alloc())) {
ast_log(LOG_WARNING, "SRTP video setup failed\n");
return -1;
}
- if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) {
+ if (p->trtp && !p->tsrtp && !(p->tsrtp = ast_sdp_srtp_alloc())) {
ast_log(LOG_WARNING, "SRTP text setup failed\n");
return -1;
}
@@ -6690,17 +6688,17 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
destroy_msg_headers(p);
if (p->srtp) {
- sip_srtp_destroy(p->srtp);
+ ast_sdp_srtp_destroy(p->srtp);
p->srtp = NULL;
}
if (p->vsrtp) {
- sip_srtp_destroy(p->vsrtp);
+ ast_sdp_srtp_destroy(p->vsrtp);
p->vsrtp = NULL;
}
if (p->tsrtp) {
- sip_srtp_destroy(p->tsrtp);
+ ast_sdp_srtp_destroy(p->tsrtp);
p->tsrtp = NULL;
}
@@ -10154,7 +10152,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
secure_audio = 1;
if (p->srtp) {
- ast_set_flag(p->srtp, SRTP_CRYPTO_OFFER_OK);
+ ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
}
} else if (!strcmp(protocol, "RTP/SAVP") || !strcmp(protocol, "RTP/SAVPF")) {
secure_audio = 1;
@@ -10235,8 +10233,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
secure_video = 1;
- if (p->vsrtp || (p->vsrtp = sip_srtp_alloc())) {
- ast_set_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK);
+ if (p->vsrtp || (p->vsrtp = ast_sdp_srtp_alloc())) {
+ ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
}
} else if (!strcmp(protocol, "RTP/SAVP") || !strcmp(protocol, "RTP/SAVPF")) {
secure_video = 1;
@@ -10516,7 +10514,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
goto process_sdp_cleanup;
}
- if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
+ if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK)))) {
ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
res = -1;
goto process_sdp_cleanup;
@@ -10528,7 +10526,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
goto process_sdp_cleanup;
}
- if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) {
+ if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK)))) {
ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n");
res = -1;
goto process_sdp_cleanup;
@@ -12993,52 +12991,20 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
}
}
-static void get_crypto_attrib(struct sip_pvt *p, struct sip_srtp *srtp, const char **a_crypto)
+static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
{
- int taglen = 80;
+ char *a_crypto;
+ char *orig_crypto;
- /* Set encryption properties */
- if (srtp) {
- if (!srtp->crypto) {
- srtp->crypto = sdp_crypto_setup();
- }
-
- if (p->dtls_cfg.enabled) {
- /* If DTLS-SRTP is enabled the key details will be pulled from TLS */
- return;
- }
-
- /* set the key length based on INVITE or settings */
- if (ast_test_flag(srtp, SRTP_CRYPTO_TAG_80)) {
- taglen = 80;
- } else if (ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32) ||
- ast_test_flag(srtp, SRTP_CRYPTO_TAG_32)) {
- taglen = 32;
- }
-
- if (srtp->crypto && (sdp_crypto_offer(srtp->crypto, taglen) >= 0)) {
- *a_crypto = sdp_crypto_attrib(srtp->crypto);
- }
-
- if (!*a_crypto) {
- ast_log(LOG_WARNING, "No SRTP key management enabled\n");
- }
+ if (!srtp) {
+ return NULL;
}
-}
-static char *get_sdp_rtp_profile(const struct sip_pvt *p, unsigned int secure, struct ast_rtp_instance *instance)
-{
- struct ast_rtp_engine_dtls *dtls;
-
- if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) {
- return ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF) ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
- } else {
- if (ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)) {
- return secure ? "RTP/SAVPF" : "RTP/AVPF";
- } else {
- return secure ? "RTP/SAVP" : "RTP/AVP";
- }
+ orig_crypto = ast_strdupa(ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32));
+ if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) {
+ return NULL;
}
+ return a_crypto;
}
/*! \brief Add Session Description Protocol message
@@ -13079,9 +13045,9 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
struct ast_str *a_video = ast_str_create(256); /* Attributes for video */
struct ast_str *a_text = ast_str_create(256); /* Attributes for text */
struct ast_str *a_modem = ast_str_alloca(1024); /* Attributes for modem */
- const char *a_crypto = NULL;
- const char *v_a_crypto = NULL;
- const char *t_a_crypto = NULL;
+ RAII_VAR(char *, a_crypto, NULL, ast_free);
+ RAII_VAR(char *, v_a_crypto, NULL, ast_free);
+ RAII_VAR(char *, t_a_crypto, NULL, ast_free);
int x;
struct ast_format tmp_fmt;
@@ -13199,9 +13165,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
/* Ok, we need video. Let's add what we need for video and set codecs.
Video is handled differently than audio since we can not transcode. */
if (needvideo) {
- get_crypto_attrib(p, p->vsrtp, &v_a_crypto);
+ v_a_crypto = crypto_get_attrib(p->vsrtp, p->dtls_cfg.enabled,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
ast_str_append(&m_video, 0, "m=video %d %s", ast_sockaddr_port(&vdest),
- get_sdp_rtp_profile(p, v_a_crypto ? 1 : 0, p->vrtp));
+ ast_sdp_get_rtp_profile(v_a_crypto ? 1 : 0, p->vrtp,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
/* Build max bitrate string */
if (p->maxcallbitrate)
@@ -13224,9 +13192,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
if (needtext) {
if (sipdebug_text)
ast_verbose("Lets set up the text sdp\n");
- get_crypto_attrib(p, p->tsrtp, &t_a_crypto);
+ t_a_crypto = crypto_get_attrib(p->tsrtp, p->dtls_cfg.enabled,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
ast_str_append(&m_text, 0, "m=text %d %s", ast_sockaddr_port(&tdest),
- get_sdp_rtp_profile(p, t_a_crypto ? 1 : 0, p->trtp));
+ ast_sdp_get_rtp_profile(t_a_crypto ? 1 : 0, p->trtp,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
if (debug) { /* XXX should I use tdest below ? */
ast_verbose("Text is at %s\n", ast_sockaddr_stringify(&taddr));
}
@@ -13245,9 +13215,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
/* We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us */
- get_crypto_attrib(p, p->srtp, &a_crypto);
+ a_crypto = crypto_get_attrib(p->srtp, p->dtls_cfg.enabled,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_SRTP_TAG_32));
ast_str_append(&m_audio, 0, "m=audio %d %s", ast_sockaddr_port(&dest),
- get_sdp_rtp_profile(p, a_crypto ? 1 : 0, p->rtp));
+ ast_sdp_get_rtp_profile(a_crypto ? 1 : 0, p->rtp,
+ ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)));
/* Now, start adding audio codecs. These are added in this order:
- First what was requested by the calling channel
@@ -25767,7 +25739,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)));
} else if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
/* If this is not a re-invite or something to ignore - it's critical */
- if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
+ if (p->srtp && !ast_test_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK)) {
ast_log(LOG_WARNING, "Target does not support required crypto\n");
transmit_response_reliable(p, "488 Not Acceptable Here (crypto)", req);
} else {
@@ -32791,22 +32763,7 @@ static void sip_send_all_mwi_subscriptions(void)
} while (0));
}
-/* SRTP */
-static int setup_srtp(struct sip_srtp **srtp)
-{
- if (!ast_rtp_engine_srtp_is_registered()) {
- ast_debug(1, "No SRTP module loaded, can't setup SRTP session.\n");
- return -1;
- }
-
- if (!(*srtp = sip_srtp_alloc())) { /* Allocate SRTP data structure */
- return -1;
- }
-
- return 0;
-}
-
-static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a)
+static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp, const char *a)
{
struct ast_rtp_engine_dtls *dtls;
@@ -32819,27 +32776,28 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc
if (strncasecmp(a, "crypto:", 7)) {
return FALSE;
}
+ /* skip "crypto:" */
+ a += strlen("crypto:");
+
if (!*srtp) {
if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
ast_log(LOG_WARNING, "Ignoring unexpected crypto attribute in SDP answer\n");
return FALSE;
}
- if (setup_srtp(srtp) < 0) {
+ if (!(*srtp = ast_sdp_srtp_alloc())) {
return FALSE;
}
}
- if (!(*srtp)->crypto && !((*srtp)->crypto = sdp_crypto_setup())) {
+ if (!(*srtp)->crypto && !((*srtp)->crypto = ast_sdp_crypto_alloc())) {
return FALSE;
}
- if (sdp_crypto_process((*srtp)->crypto, a, rtp, *srtp) < 0) {
+ if (ast_sdp_crypto_process(rtp, *srtp, a) < 0) {
return FALSE;
}
- ast_set_flag(*srtp, SRTP_CRYPTO_OFFER_OK);
-
if ((dtls = ast_rtp_instance_get_dtls(rtp))) {
dtls->stop(rtp);
p->dtls_cfg.enabled = 0;
diff --git a/channels/sip/include/sdp_crypto.h b/channels/sip/include/sdp_crypto.h
deleted file mode 100644
index da1035e87..000000000
--- a/channels/sip/include/sdp_crypto.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2006 - 2007, Mikael Magnusson
- *
- * Mikael Magnusson <mikma@users.sourceforge.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file sdp_crypto.h
- *
- * \brief SDP Security descriptions
- *
- * Specified in RFC 4568
- *
- * \author Mikael Magnusson <mikma@users.sourceforge.net>
- */
-
-#ifndef _SDP_CRYPTO_H
-#define _SDP_CRYPTO_H
-
-#include <asterisk/rtp_engine.h>
-
-struct sdp_crypto;
-struct sip_srtp;
-
-/*! \brief Initialize an return an sdp_crypto struct
- *
- * \details
- * This function allocates a new sdp_crypto struct and initializes its values
- *
- * \retval NULL on failure
- * \retval a pointer to a new sdp_crypto structure
- */
-struct sdp_crypto *sdp_crypto_setup(void);
-
-/*! \brief Destroy a previously allocated sdp_crypto struct */
-void sdp_crypto_destroy(struct sdp_crypto *crypto);
-
-/*! \brief Parse the a=crypto line from SDP and set appropriate values on the
- * sdp_crypto struct.
- *
- * \param p A valid sdp_crypto struct
- * \param attr the a:crypto line from SDP
- * \param rtp The rtp instance associated with the SDP being parsed
- * \param srtp SRTP structure
- *
- * \retval 0 success
- * \retval nonzero failure
- */
-int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp);
-
-
-/*! \brief Generate an SRTP a=crypto offer
- *
- * \details
- * The offer is stored on the sdp_crypto struct in a_crypto
- *
- * \param p A valid sdp_crypto struct
- * \param taglen Length
- *
- * \retval 0 success
- * \retval nonzero failure
- */
-int sdp_crypto_offer(struct sdp_crypto *p, int taglen);
-
-
-/*! \brief Return the a_crypto value of the sdp_crypto struct
- *
- * \param p An sdp_crypto struct that has had sdp_crypto_offer called
- *
- * \retval The value of the a_crypto for p
- */
-const char *sdp_crypto_attrib(struct sdp_crypto *p);
-
-#endif /* _SDP_CRYPTO_H */
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 0adde37f2..8b4672b25 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -1165,9 +1165,9 @@ struct sip_pvt {
AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
struct sip_invite_param *options; /*!< Options for INVITE */
struct sip_st_dlg *stimer; /*!< SIP Session-Timers */
- struct sip_srtp *srtp; /*!< Structure to hold Secure RTP session data for audio */
- struct sip_srtp *vsrtp; /*!< Structure to hold Secure RTP session data for video */
- struct sip_srtp *tsrtp; /*!< Structure to hold Secure RTP session data for text */
+ struct ast_sdp_srtp *srtp; /*!< Structure to hold Secure RTP session data for audio */
+ struct ast_sdp_srtp *vsrtp; /*!< Structure to hold Secure RTP session data for video */
+ struct ast_sdp_srtp *tsrtp; /*!< Structure to hold Secure RTP session data for text */
int red; /*!< T.140 RTP Redundancy */
int hangupcause; /*!< Storage of hangupcause copied from our owner before we disconnect from the AST channel (only used at hangup) */
diff --git a/channels/sip/include/srtp.h b/channels/sip/include/srtp.h
deleted file mode 100644
index a4ded62ca..000000000
--- a/channels/sip/include/srtp.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2006 - 2007, Mikael Magnusson
- *
- * Mikael Magnusson <mikma@users.sourceforge.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file srtp.h
- *
- * \brief SIP Secure RTP (SRTP)
- *
- * Specified in RFC 3711
- *
- * \author Mikael Magnusson <mikma@users.sourceforge.net>
- */
-
-#ifndef _SIP_SRTP_H
-#define _SIP_SRTP_H
-
-#include "sdp_crypto.h"
-
-/* SRTP flags */
-#define SRTP_ENCR_OPTIONAL (1 << 1) /* SRTP encryption optional */
-#define SRTP_CRYPTO_ENABLE (1 << 2)
-#define SRTP_CRYPTO_OFFER_OK (1 << 3)
-#define SRTP_CRYPTO_TAG_32 (1 << 4)
-#define SRTP_CRYPTO_TAG_80 (1 << 5)
-
-/*! \brief structure for secure RTP audio */
-struct sip_srtp {
- unsigned int flags;
- struct sdp_crypto *crypto;
-};
-
-/*!
- * \brief allocate a sip_srtp structure
- * \retval a new malloc'd sip_srtp structure on success
- * \retval NULL on failure
-*/
-struct sip_srtp *sip_srtp_alloc(void);
-
-/*!
- * \brief free a sip_srtp structure
- * \param srtp a sip_srtp structure
-*/
-void sip_srtp_destroy(struct sip_srtp *srtp);
-
-#endif /* _SIP_SRTP_H */
diff --git a/channels/sip/sdp_crypto.c b/channels/sip/sdp_crypto.c
deleted file mode 100644
index c27e882c2..000000000
--- a/channels/sip/sdp_crypto.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2006 - 2007, Mikael Magnusson
- *
- * Mikael Magnusson <mikma@users.sourceforge.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file sdp_crypto.c
- *
- * \brief SDP Security descriptions
- *
- * Specified in RFC 4568
- *
- * \author Mikael Magnusson <mikma@users.sourceforge.net>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/options.h"
-#include "asterisk/utils.h"
-#include "include/sdp_crypto.h"
-#include "include/srtp.h"
-
-#define SRTP_MASTER_LEN 30
-#define SRTP_MASTERKEY_LEN 16
-#define SRTP_MASTERSALT_LEN ((SRTP_MASTER_LEN) - (SRTP_MASTERKEY_LEN))
-#define SRTP_MASTER_LEN64 (((SRTP_MASTER_LEN) * 8 + 5) / 6 + 1)
-
-extern struct ast_srtp_res *res_srtp;
-extern struct ast_srtp_policy_res *res_srtp_policy;
-
-struct sdp_crypto {
- char *a_crypto;
- unsigned char local_key[SRTP_MASTER_LEN];
- char *tag;
- char local_key64[SRTP_MASTER_LEN64];
- unsigned char remote_key[SRTP_MASTER_LEN];
-};
-
-static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound);
-
-static struct sdp_crypto *sdp_crypto_alloc(void)
-{
- return ast_calloc(1, sizeof(struct sdp_crypto));
-}
-
-void sdp_crypto_destroy(struct sdp_crypto *crypto)
-{
- ast_free(crypto->a_crypto);
- crypto->a_crypto = NULL;
- ast_free(crypto->tag);
- crypto->tag = NULL;
- ast_free(crypto);
-}
-
-struct sdp_crypto *sdp_crypto_setup(void)
-{
- struct sdp_crypto *p;
- int key_len;
- unsigned char remote_key[SRTP_MASTER_LEN];
-
- if (!ast_rtp_engine_srtp_is_registered()) {
- return NULL;
- }
-
- if (!(p = sdp_crypto_alloc())) {
- return NULL;
- }
-
- if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) {
- sdp_crypto_destroy(p);
- return NULL;
- }
-
- ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64));
-
- key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key));
-
- if (key_len != SRTP_MASTER_LEN) {
- ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN);
- ast_free(p);
- return NULL;
- }
-
- if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) {
- ast_log(LOG_ERROR, "base64 encode/decode bad key\n");
- ast_free(p);
- return NULL;
- }
-
- ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64));
-
- return p;
-}
-
-static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound)
-{
- const unsigned char *master_salt = NULL;
-
- if (!ast_rtp_engine_srtp_is_registered()) {
- return -1;
- }
-
- master_salt = master_key + SRTP_MASTERKEY_LEN;
- if (res_srtp_policy->set_master_key(policy, master_key, SRTP_MASTERKEY_LEN, master_salt, SRTP_MASTERSALT_LEN) < 0) {
- return -1;
- }
-
- if (res_srtp_policy->set_suite(policy, suite_val)) {
- ast_log(LOG_WARNING, "Could not set remote SRTP suite\n");
- return -1;
- }
-
- res_srtp_policy->set_ssrc(policy, ssrc, inbound);
-
- return 0;
-}
-
-static int sdp_crypto_activate(struct sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp)
-{
- struct ast_srtp_policy *local_policy = NULL;
- struct ast_srtp_policy *remote_policy = NULL;
- struct ast_rtp_instance_stats stats = {0,};
- int res = -1;
-
- if (!ast_rtp_engine_srtp_is_registered()) {
- return -1;
- }
-
- if (!p) {
- return -1;
- }
-
- if (!(local_policy = res_srtp_policy->alloc())) {
- return -1;
- }
-
- if (!(remote_policy = res_srtp_policy->alloc())) {
- goto err;
- }
-
- if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_LOCAL_SSRC)) {
- goto err;
- }
-
- if (set_crypto_policy(local_policy, suite_val, p->local_key, stats.local_ssrc, 0) < 0) {
- goto err;
- }
-
- if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0) {
- goto err;
- }
-
- /* Add the SRTP policies */
- if (ast_rtp_instance_add_srtp_policy(rtp, remote_policy, local_policy)) {
- ast_log(LOG_WARNING, "Could not set SRTP policies\n");
- goto err;
- }
-
- ast_debug(1 , "SRTP policy activated\n");
- res = 0;
-
-err:
- if (local_policy) {
- res_srtp_policy->destroy(local_policy);
- }
-
- if (remote_policy) {
- res_srtp_policy->destroy(remote_policy);
- }
-
- return res;
-}
-
-int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp, struct sip_srtp *srtp)
-{
- char *str = NULL;
- char *tag = NULL;
- char *suite = NULL;
- char *key_params = NULL;
- char *key_param = NULL;
- char *session_params = NULL;
- char *key_salt = NULL;
- char *lifetime = NULL;
- int found = 0;
- int key_len = 0;
- int suite_val = 0;
- unsigned char remote_key[SRTP_MASTER_LEN];
- int taglen = 0;
-
- if (!ast_rtp_engine_srtp_is_registered()) {
- return -1;
- }
-
- str = ast_strdupa(attr);
-
- strsep(&str, ":");
- tag = strsep(&str, " ");
- suite = strsep(&str, " ");
- key_params = strsep(&str, " ");
- session_params = strsep(&str, " ");
-
- if (!tag || !suite) {
- ast_log(LOG_WARNING, "Unrecognized a=%s", attr);
- return -1;
- }
-
- if (!ast_strlen_zero(session_params)) {
- ast_log(LOG_WARNING, "Unsupported crypto parameters: %s", session_params);
- return -1;
- }
-
- if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
- suite_val = AST_AES_CM_128_HMAC_SHA1_80;
- ast_set_flag(srtp, SRTP_CRYPTO_TAG_80);
- taglen = 80;
- } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
- suite_val = AST_AES_CM_128_HMAC_SHA1_32;
- ast_set_flag(srtp, SRTP_CRYPTO_TAG_32);
- taglen = 32;
- } else {
- ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite);
- return -1;
- }
-
- while ((key_param = strsep(&key_params, ";"))) {
- char *method = NULL;
- char *info = NULL;
-
- method = strsep(&key_param, ":");
- info = strsep(&key_param, ";");
-
- if (!strcmp(method, "inline")) {
- key_salt = strsep(&info, "|");
- lifetime = strsep(&info, "|");
-
- if (lifetime) {
- ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n", attr);
- continue;
- }
-
- found = 1;
- break;
- }
- }
-
- if (!found) {
- ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n");
- return -1;
- }
-
- if ((key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key))) != SRTP_MASTER_LEN) {
- ast_log(LOG_WARNING, "SRTP descriptions key %d != %d\n", key_len, SRTP_MASTER_LEN);
- return -1;
- }
-
- if (!memcmp(p->remote_key, remote_key, sizeof(p->remote_key))) {
- ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n");
- return 0;
- }
- memcpy(p->remote_key, remote_key, sizeof(p->remote_key));
-
- if (sdp_crypto_activate(p, suite_val, remote_key, rtp) < 0) {
- return -1;
- }
-
- if (!p->tag) {
- ast_log(LOG_DEBUG, "Accepting crypto tag %s\n", tag);
- p->tag = ast_strdup(tag);
- if (!p->tag) {
- ast_log(LOG_ERROR, "Could not allocate memory for tag\n");
- return -1;
- }
- }
-
- /* Finally, rebuild the crypto line */
- return sdp_crypto_offer(p, taglen);
-}
-
-int sdp_crypto_offer(struct sdp_crypto *p, int taglen)
-{
- /* Rebuild the crypto line */
- if (p->a_crypto) {
- ast_free(p->a_crypto);
- }
-
- if (ast_asprintf(&p->a_crypto, "a=crypto:%s AES_CM_128_HMAC_SHA1_%i inline:%s\r\n",
- p->tag ? p->tag : "1", taglen, p->local_key64) == -1) {
- ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n");
- return -1;
- }
-
- ast_log(LOG_DEBUG, "Crypto line: %s", p->a_crypto);
-
- return 0;
-}
-
-const char *sdp_crypto_attrib(struct sdp_crypto *p)
-{
- return p->a_crypto;
-}
diff --git a/channels/sip/srtp.c b/channels/sip/srtp.c
deleted file mode 100644
index 8b2718fc3..000000000
--- a/channels/sip/srtp.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2006 - 2007, Mikael Magnusson
- *
- * Mikael Magnusson <mikma@users.sourceforge.net>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file srtp.c
- *
- * \brief SIP Secure RTP (SRTP)
- *
- * Specified in RFC 3711
- *
- * \author Mikael Magnusson <mikma@users.sourceforge.net>
- */
-
-/*** MODULEINFO
- <support_level>core</support_level>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/utils.h"
-#include "include/srtp.h"
-
-struct sip_srtp *sip_srtp_alloc(void)
-{
- struct sip_srtp *srtp;
-
- srtp = ast_calloc(1, sizeof(*srtp));
-
- return srtp;
-}
-
-void sip_srtp_destroy(struct sip_srtp *srtp)
-{
- if (srtp->crypto) {
- sdp_crypto_destroy(srtp->crypto);
- }
- srtp->crypto = NULL;
- ast_free(srtp);
-}