[svn-commits] kharwell: branch kharwell/gulp_notify r392721 - in /team/kharwell/gulp_notify...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jun 24 09:54:17 CDT 2013


Author: kharwell
Date: Mon Jun 24 09:54:04 2013
New Revision: 392721

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392721
Log:
Multiple revisions 392564-392565,392586,392607,392627,392647,392667,392676,392700

........
  r392564 | mjordan | 2013-06-22 08:58:07 -0500 (Sat, 22 Jun 2013) | 26 lines
  
  Fix a deadlock and possible crash in res_fax
  
  This patch fixes two bugs.
  (1) It unlocks the channel in the framehook handlers before attempting to grab
      the peer from the bridge. The locking order for the bridging framework is
      bridge first, then channel - having the channel locked while attempting to
      obtain the bridge lock causes a locking inversion and a deadlock. This
      patch bumps the channel ref count prior to releasing the lock in the
      framehook to avoid lifetime issues.
  
      Note that this does expose a subtle problem in framehooks; that is,
      something could modify the framehook list while we are executing, causing
      issues in the framehook list traversal that the callback executes in.
      Fixing this is a much larger problem that is beyond the scope of this
      patch - (a) we already unlock the channel in this particular framehook
      and we haven't run into a problem yet (as modifying the framehook list
      when a channel is about to perform a fax gateway would be a very odd
      operation) and (b) migrating to an ao2 container of framehooks would be
      more invasive at this point. See the referenced ASTERISK issue for more
      information.
  (2) Directly packing channel variables into a JSON object turned out to be
      unsafe. A condition existed where the strings in the JSON blob were no
      longer safe to be accessed if the channel object itself was disposed of.
  
  (issue ASTERISK-21951)
........
  r392565 | file | 2013-06-22 09:03:22 -0500 (Sat, 22 Jun 2013) | 24 lines
  
  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.
........
  r392586 | file | 2013-06-22 09:26:25 -0500 (Sat, 22 Jun 2013) | 20 lines
  
  Make sorcery details opaque and add extended fields.
  
  Sorcery specific object information is now opaque and allocated with the object.
  This means that modules do not need to be recompiled if the sorcery specific part
  is changed. It also means that sorcery can store additional information on objects
  and ensure it is freed or the reference count decreased when the object goes away.
  
  To facilitate the above a generic sorcery allocator function has been added which
  also ensures that allocated objects do not have a lock.
  
  Extended fields have been added thanks to all of the above which allows specific fields
  to be marked as extended, and thus simply stored as-is within the object. Type safety
  is *NOT* enforced on these fields. A consumer of them has to query and ultimately perform
  their own safety check. What does this mean? Extra modules can extend already defined
  structures without having to modify them.
  
  Tests have also been included to verify extended field functionality.
  
  Review: https://reviewboard.asterisk.org/r/2585/
........
  r392607 | mjordan | 2013-06-22 17:42:34 -0500 (Sat, 22 Jun 2013) | 6 lines
  
  Properly extract channel variables for the SendFAX/ReceiveFAX Stasis messages
  
  By the time something extracts the pointers from ast_json_pack, the channels
  will already be disposed of. This patch properly pulls the information out of
  the variables and packs them into the JSON blob.
........
  r392627 | file | 2013-06-22 19:02:01 -0500 (Sat, 22 Jun 2013) | 7 lines
  
  Fix a bug where messages were getting duplicated on AMI.
  
  This was caused by forwarding all endpoint messages to manager which includes
  channel messages that are related to the endpoint. This change causes only
  the PeerStatus messages to be forwarded to manager thus eliminating the
  duplicate channel messages.
........
  r392647 | file | 2013-06-23 08:24:18 -0500 (Sun, 23 Jun 2013) | 2 lines
  
  Add missing ast_sorcery_generic_alloc conversions.
........
  r392667 | file | 2013-06-23 13:59:36 -0500 (Sun, 23 Jun 2013) | 2 lines
  
  Add some more missing ast_sorcery_generic_alloc conversions.
........
  r392676 | mjordan | 2013-06-23 14:19:30 -0500 (Sun, 23 Jun 2013) | 11 lines
  
  Properly pack the parameters into ast_json_pack when sending a send fax message
  
  This patch properly packs the parameters into the send fax message so that it
  actually work.
  
  Missing a ',' between two string fields can be difficult to debug, particularly
  when the actual packing succeeds. Interestingly enough, this didn't actually
  crash until the JSON blob we deref'd and disposed of. Since that happened in
  a different thread, it was pretty tough to track down.
........
  r392700 | kmoore | 2013-06-24 08:49:20 -0500 (Mon, 24 Jun 2013) | 20 lines
  
  Index installed sounds and implement ARI sounds queries
  
  This adds support for stasis/sounds and stasis/sounds/{ID} queries via
  the Asterisk RESTful Interface (ARI, formerly Stasis-HTTP).
  
  The following changes have been made to accomplish this:
  * A modular indexer was created for local media.
  * A new function to get an ast_format associated with a file extension
    was added.  
  * Modifications were made to the built-in HTTP server so that URI
    decoding could be deferred to the URI handler when necessary.
  * The Stasis-HTTP sounds JSON documentation was modified to handle
    cases where multiple languages are installed in different formats.
  * Register and Unregister events for formats were added to the system
    topic.
  
  (closes issue ASTERISK-21584)
  (closes issue ASTERISK-21585)
  Review: https://reviewboard.asterisk.org/r/2507/
........

Merged revisions 392564-392565,392586,392607,392627,392647,392667,392676,392700 from http://svn.asterisk.org/svn/asterisk/trunk

Added:
    team/kharwell/gulp_notify/include/asterisk/media_index.h
      - copied unchanged from r392700, trunk/include/asterisk/media_index.h
    team/kharwell/gulp_notify/include/asterisk/res_sip_exten_state.h
      - copied unchanged from r392700, trunk/include/asterisk/res_sip_exten_state.h
    team/kharwell/gulp_notify/include/asterisk/sdp_srtp.h
      - copied unchanged from r392700, trunk/include/asterisk/sdp_srtp.h
    team/kharwell/gulp_notify/include/asterisk/sounds_index.h
      - copied unchanged from r392700, trunk/include/asterisk/sounds_index.h
    team/kharwell/gulp_notify/main/media_index.c
      - copied unchanged from r392700, trunk/main/media_index.c
    team/kharwell/gulp_notify/main/sdp_srtp.c
      - copied unchanged from r392700, trunk/main/sdp_srtp.c
    team/kharwell/gulp_notify/main/sounds_index.c
      - copied unchanged from r392700, trunk/main/sounds_index.c
    team/kharwell/gulp_notify/res/res_sip/security_events.c
      - copied unchanged from r392700, trunk/res/res_sip/security_events.c
    team/kharwell/gulp_notify/res/res_sip_diversion.c
      - copied unchanged from r392700, trunk/res/res_sip_diversion.c
    team/kharwell/gulp_notify/res/res_sip_endpoint_identifier_anonymous.c
      - copied unchanged from r392700, trunk/res/res_sip_endpoint_identifier_anonymous.c
    team/kharwell/gulp_notify/res/res_sip_exten_state.c
      - copied unchanged from r392700, trunk/res/res_sip_exten_state.c
    team/kharwell/gulp_notify/res/res_sip_exten_state.exports.in
      - copied unchanged from r392700, trunk/res/res_sip_exten_state.exports.in
    team/kharwell/gulp_notify/res/res_sip_messaging.c
      - copied unchanged from r392700, trunk/res/res_sip_messaging.c
    team/kharwell/gulp_notify/res/res_sip_one_touch_record_info.c
      - copied unchanged from r392700, trunk/res/res_sip_one_touch_record_info.c
    team/kharwell/gulp_notify/res/res_sip_pidf.c
      - copied unchanged from r392700, trunk/res/res_sip_pidf.c
    team/kharwell/gulp_notify/res/res_sip_refer.c
      - copied unchanged from r392700, trunk/res/res_sip_refer.c
    team/kharwell/gulp_notify/res/res_sip_registrar_expire.c
      - copied unchanged from r392700, trunk/res/res_sip_registrar_expire.c
    team/kharwell/gulp_notify/res/res_sip_transport_websocket.c
      - copied unchanged from r392700, trunk/res/res_sip_transport_websocket.c
Removed:
    team/kharwell/gulp_notify/channels/sip/include/sdp_crypto.h
    team/kharwell/gulp_notify/channels/sip/include/srtp.h
    team/kharwell/gulp_notify/channels/sip/sdp_crypto.c
    team/kharwell/gulp_notify/channels/sip/srtp.c
Modified:
    team/kharwell/gulp_notify/   (props changed)
    team/kharwell/gulp_notify/channels/chan_gulp.c
    team/kharwell/gulp_notify/channels/chan_sip.c
    team/kharwell/gulp_notify/channels/sip/include/sip.h
    team/kharwell/gulp_notify/configs/res_sip.conf.sample
    team/kharwell/gulp_notify/include/asterisk/_private.h
    team/kharwell/gulp_notify/include/asterisk/file.h
    team/kharwell/gulp_notify/include/asterisk/format.h
    team/kharwell/gulp_notify/include/asterisk/http.h
    team/kharwell/gulp_notify/include/asterisk/res_sip.h
    team/kharwell/gulp_notify/include/asterisk/res_sip_pubsub.h
    team/kharwell/gulp_notify/include/asterisk/res_sip_session.h
    team/kharwell/gulp_notify/include/asterisk/sorcery.h
    team/kharwell/gulp_notify/main/asterisk.c
    team/kharwell/gulp_notify/main/file.c
    team/kharwell/gulp_notify/main/http.c
    team/kharwell/gulp_notify/main/manager_endpoints.c
    team/kharwell/gulp_notify/main/pbx.c
    team/kharwell/gulp_notify/main/sorcery.c
    team/kharwell/gulp_notify/res/res_fax.c
    team/kharwell/gulp_notify/res/res_sip.c
    team/kharwell/gulp_notify/res/res_sip.exports.in
    team/kharwell/gulp_notify/res/res_sip/config_auth.c
    team/kharwell/gulp_notify/res/res_sip/config_domain_aliases.c
    team/kharwell/gulp_notify/res/res_sip/config_transport.c
    team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h
    team/kharwell/gulp_notify/res/res_sip/location.c
    team/kharwell/gulp_notify/res/res_sip/sip_configuration.c
    team/kharwell/gulp_notify/res/res_sip/sip_distributor.c
    team/kharwell/gulp_notify/res/res_sip/sip_options.c
    team/kharwell/gulp_notify/res/res_sip_acl.c
    team/kharwell/gulp_notify/res/res_sip_caller_id.c
    team/kharwell/gulp_notify/res/res_sip_dtmf_info.c
    team/kharwell/gulp_notify/res/res_sip_endpoint_identifier_ip.c
    team/kharwell/gulp_notify/res/res_sip_outbound_registration.c
    team/kharwell/gulp_notify/res/res_sip_pubsub.c
    team/kharwell/gulp_notify/res/res_sip_pubsub.exports.in
    team/kharwell/gulp_notify/res/res_sip_registrar.c
    team/kharwell/gulp_notify/res/res_sip_sdp_rtp.c
    team/kharwell/gulp_notify/res/res_sip_session.c
    team/kharwell/gulp_notify/res/res_sip_session.exports.in
    team/kharwell/gulp_notify/res/res_stasis_http.c
    team/kharwell/gulp_notify/res/stasis_http/resource_sounds.c
    team/kharwell/gulp_notify/rest-api/api-docs/sounds.json
    team/kharwell/gulp_notify/tests/test_sorcery.c
    team/kharwell/gulp_notify/tests/test_sorcery_astdb.c
    team/kharwell/gulp_notify/tests/test_sorcery_realtime.c

Propchange: team/kharwell/gulp_notify/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Jun 24 09:54:04 2013
@@ -1,1 +1,1 @@
-/trunk:1-392542
+/trunk:1-392720

Modified: team/kharwell/gulp_notify/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/channels/chan_gulp.c?view=diff&rev=392721&r1=392720&r2=392721
==============================================================================
--- team/kharwell/gulp_notify/channels/chan_gulp.c (original)
+++ team/kharwell/gulp_notify/channels/chan_gulp.c Mon Jun 24 09:54:04 2013
@@ -53,6 +53,7 @@
 #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 @@
 			<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 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 @@
 	.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 @@
 	.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 @@
 
 	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 @@
 	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 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 @@
 		return &ast_null_frame;
 	}
 
-	f = ast_rtp_instance_read(media->rtp, rtcp);
-
-	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 (!(f = ast_rtp_instance_read(media->rtp, rtcp))) {
+		return f;
+	}
+
+	if (f->frametype != AST_FRAME_VOICE) {
+		return f;
+	}
+
+	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 @@
 		.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)) {
@@ -781,6 +920,40 @@
 		return -1;
 	}
 	ast_sip_session_send_request(session, tdata);
+
+	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;
 }
@@ -797,7 +970,12 @@
 	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 @@
 	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:
@@ -857,6 +1046,13 @@
 	case AST_CONTROL_SRCUPDATE:
 		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;
@@ -867,21 +1063,141 @@
 		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;
 		}
 	}
 
 	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 */
@@ -1014,18 +1330,18 @@
 
 static int call(void *data)
 {
-	pjsip_tx_data *packet;
 	struct ast_sip_session *session = data;
-
-	if (pjsip_inv_invite(session->inv_session, &packet) != PJ_SUCCESS) {
+	pjsip_tx_data *tdata;
+
+	int res = ast_sip_session_create_invite(session, &tdata);
+
+	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 @@
 	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 @@
 	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 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 @@
 		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);
 
@@ -1428,6 +1809,12 @@
 
 	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 @@
 		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 @@
 	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 @@
 /*! \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);

Modified: team/kharwell/gulp_notify/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/channels/chan_sip.c?view=diff&rev=392721&r1=392720&r2=392721
==============================================================================
--- team/kharwell/gulp_notify/channels/chan_sip.c (original)
+++ team/kharwell/gulp_notify/channels/chan_sip.c Mon Jun 24 09:54:04 2013
@@ -285,8 +285,7 @@
 #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 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 @@
 }
 
 /*! \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 @@
 		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 @@
 			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 @@
 	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 @@
 					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 @@
 				} 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 @@
 		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 @@
 		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_crypto_attrib(struct sip_pvt *p, struct sip_srtp *srtp, const char **a_crypto)
-{
-	int taglen = 80;
-
-	/* 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");
-		}
-	}
-}
-
-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";
-		}
-	}
+static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
+{
+	char *a_crypto;
+	char *orig_crypto;
+
+	if (!srtp) {
+		return NULL;
+	}
+
+	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 @@
 	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 @@
 		/* 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 @@
 		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,

[... 4651 lines stripped ...]



More information about the svn-commits mailing list