[svn-commits] file: branch file/gulp_fax r394436 - in /team/file/gulp_fax: channels/ includ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 16 08:37:48 CDT 2013


Author: file
Date: Tue Jul 16 08:37:45 2013
New Revision: 394436

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394436
Log:
Add current progress!

1. It's now possible for an SDP handler to request that a re-invite be suspended and resumed at a later time. This is preliminary code.
2. chan_gulp will now react to T.38 actions as expected (indicate / queryoption)
3. Incoming T.38 re-invites are now rejected as expected

With all of this I've got the signaling going correctly and UDPTL flowing.

Modified:
    team/file/gulp_fax/channels/chan_gulp.c
    team/file/gulp_fax/include/asterisk/res_sip_session.h
    team/file/gulp_fax/res/res_sip_session.c
    team/file/gulp_fax/res/res_sip_session.exports.in
    team/file/gulp_fax/res/res_sip_t38.c

Modified: team/file/gulp_fax/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/channels/chan_gulp.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/channels/chan_gulp.c (original)
+++ team/file/gulp_fax/channels/chan_gulp.c Tue Jul 16 08:37:45 2013
@@ -788,6 +788,8 @@
 			res = ast_rtp_instance_write(media->rtp, frame);
 		}
 		break;
+	case AST_FRAME_MODEM:
+		break;
 	default:
 		ast_log(LOG_WARNING, "Can't send %d type frames with Gulp\n", frame->frametype);
 		break;
@@ -907,10 +909,29 @@
 	struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
 	struct ast_sip_session *session = pvt->session;
 	int res = -1;
+	enum ast_sip_session_t38state state = T38_STATE_UNAVAILABLE;
 
 	switch (option) {
 	case AST_OPTION_T38_STATE:
-		*((enum ast_t38_state *) data) = session->endpoint->t38udptl ? T38_STATE_UNKNOWN : T38_STATE_UNAVAILABLE;
+		if (session->endpoint->t38udptl) {
+			switch (session->t38state) {
+			case T38_LOCAL_REINVITE:
+			case T38_PEER_REINVITE:
+				state = T38_STATE_NEGOTIATING;
+				break;
+			case T38_ENABLED:
+				state = T38_STATE_NEGOTIATED;
+				break;
+			case T38_REJECTED:
+				state = T38_STATE_REJECTED;
+				break;
+			default:
+				state = T38_STATE_UNKNOWN;
+				break;
+			}
+		}
+
+		*((enum ast_t38_state *) data) = state;
 		res = 0;
 
 		break;
@@ -1142,6 +1163,18 @@
 		} else {
 			res = -1;
 		}
+		break;
+	case AST_CONTROL_T38_PARAMETERS:
+		res = 0;
+
+		if (session->t38state == T38_PEER_REINVITE) {
+			const struct ast_control_t38_parameters *parameters = data;
+
+			if (parameters->request_response == AST_T38_REQUEST_PARMS) {
+				res = AST_T38_REQUEST_PARMS;
+			}
+		}
+
 		break;
 	case -1:
 		res = -1;

Modified: team/file/gulp_fax/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/include/asterisk/res_sip_session.h?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/include/asterisk/res_sip_session.h (original)
+++ team/file/gulp_fax/include/asterisk/res_sip_session.h Tue Jul 16 08:37:45 2013
@@ -45,6 +45,15 @@
 struct ast_rtp_instance;
 struct ast_dsp;
 struct ast_udptl;
+
+/*! \brief T.38 states for a session */
+enum ast_sip_session_t38state {
+	T38_DISABLED = 0,   /*!< Not enabled */
+	T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
+	T38_PEER_REINVITE,  /*!< Offered from peer - REINVITE */
+	T38_ENABLED,        /*!< Negotiated (enabled) */
+	T38_REJECTED,       /*!< Refused */
+};
 
 struct ast_sip_session_sdp_handler;
 
@@ -119,6 +128,10 @@
 	struct ast_dsp *dsp;
 	/* Whether the termination of the session should be deferred */
 	unsigned int defer_terminate:1;
+	/* Deferred incoming re-invite */
+	pjsip_rx_data *deferred_reinvite;
+	/* Current T.38 state */
+	enum ast_sip_session_t38state t38state;
 };
 
 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
@@ -216,6 +229,17 @@
 	/*! An identifier for this handler */
 	const char *id;
 	/*!
+	 * \brief Defer re-invited stream
+	 * \param session The session for which the media is being re-invited
+	 * \param session_media The media being reinvited
+	 * \param sdp The entire SDP.
+	 * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
+	 * \retval <0 Re-invite should be deferred. No further operation will take place.
+	 * \retval >0 The stream was explicitly not deferred by this handler. No further handler of this stream type will be called.
+	 * \note This is optional, if not implemented the stream is assumed to not be deferred.
+	 */
+	int (*defer_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
+	/*!
 	 * \brief Set session details based on a stream in an incoming SDP offer or answer
 	 * \param session The session for which the media is being negotiated
 	 * \param session_media The media to be setup for this session
@@ -512,4 +536,13 @@
  */
 struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg);
 
+/*!
+ * \brief Resumes processing of a deferred incoming re-invite
+ *
+ * \param session The session which has a pending incoming re-invite
+ *
+ * \note It is possible for the defer_incoming_sdp_stream callback to be called yet again when this is invoked
+ */
+void ast_sip_session_resume_reinvite(struct ast_sip_session *session);
+
 #endif /* _RES_SIP_SESSION_H */

Modified: team/file/gulp_fax/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_session.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_session.c (original)
+++ team/file/gulp_fax/res/res_sip_session.c Tue Jul 16 08:37:45 2013
@@ -787,6 +787,121 @@
 	.start = session_start,
 	.stop = session_stop,
 	.on_rx_request = session_on_rx_request,
+};
+
+static int handle_deferring_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
+{
+	int i;
+	if (validate_incoming_sdp(sdp)) {
+		return -1;
+	}
+
+	for (i = 0; i < sdp->media_count; ++i) {
+		/* See if there are registered handlers for this media stream type */
+		char media[20];
+		struct ast_sip_session_sdp_handler *handler;
+		RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+		RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+
+		/* We need a null-terminated version of the media string */
+		ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
+
+		session_media = ao2_find(session->media, media, OBJ_KEY);
+		if (!session_media) {
+			/* if the session_media doesn't exist, there weren't
+			 * any handlers at the time of its creation */
+			continue;
+		}
+
+		if (session_media->handler && session_media->handler->defer_incoming_sdp_stream) {
+			int res;
+			handler = session_media->handler;
+			res = handler->defer_incoming_sdp_stream(
+				session, session_media, sdp, sdp->media[i]);
+			if (res <= 0) {
+				return 1;
+			}
+			if (res > 0) {
+				/* Handled by this handler. Move to the next stream */
+				continue;
+			}
+		}
+
+		handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+		if (!handler_list) {
+			ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+			continue;
+		}
+		AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+			int res;
+			if (session_media->handler) {
+				/* There is only one slot for this stream type and it has already been claimed
+				 * so it will go unhandled */
+				break;
+			}
+			if (!handler->defer_incoming_sdp_stream) {
+				continue;
+			}
+			res = handler->defer_incoming_sdp_stream(session, session_media, sdp, sdp->media[i]);
+			if (res < 0) {
+				return 1;
+			}
+			if (res > 0) {
+				/* Handled by this handler. Move to the next stream */
+				session_media->handler = handler;
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata)
+{
+	pjsip_dialog *dlg;
+	pjsip_inv_session *inv_session;
+	struct ast_sip_session *session;
+	pjsip_rdata_sdp_info *sdp_info;
+
+	if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
+		!(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
+		!(inv_session = pjsip_dlg_get_inv_session(dlg)) ||
+		!(session = inv_session->mod_data[session_module.id])) {
+		return PJ_FALSE;
+	}
+
+	/* XXX Reject new re-invite if deferred exists and not a retransmission */
+	if (session->deferred_reinvite) {
+		return PJ_TRUE;
+	}
+
+	if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
+		(sdp_info->sdp_err != PJ_SUCCESS) ||
+		!sdp_info->sdp ||
+		!handle_deferring_sdp(session, sdp_info->sdp)) {
+		return PJ_FALSE;
+	}
+
+	pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
+
+	return PJ_TRUE;
+}
+
+void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
+{
+	if (!session->deferred_reinvite) {
+		return;
+	}
+
+	pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), session->deferred_reinvite, NULL, NULL);
+	pjsip_rx_data_free_cloned(session->deferred_reinvite);
+	session->deferred_reinvite = NULL;
+}
+
+static pjsip_module session_reinvite_module = {
+	.name = { "Session Re-Invite Module", 24 },
+	.priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
+	.on_rx_request = session_reinvite_on_rx_request,
 };
 
 void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
@@ -1929,12 +2044,14 @@
 	if (ast_sip_register_service(&session_module)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
+	ast_sip_register_service(&session_reinvite_module);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 static int unload_module(void)
 {
 	ast_sip_unregister_service(&session_module);
+	ast_sip_unregister_service(&session_reinvite_module);
 	if (nat_hook) {
 		ast_sorcery_delete(ast_sip_get_sorcery(), nat_hook);
 		nat_hook = NULL;

Modified: team/file/gulp_fax/res/res_sip_session.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_session.exports.in?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_session.exports.in (original)
+++ team/file/gulp_fax/res/res_sip_session.exports.in Tue Jul 16 08:37:45 2013
@@ -16,6 +16,7 @@
 		LINKER_SYMBOL_PREFIXast_sip_session_create_invite;
 		LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing;
 		LINKER_SYMBOL_PREFIXast_sip_dialog_get_session;
+		LINKER_SYMBOL_PREFIXast_sip_session_resume_reinvite;
 	local:
 		*;
 };

Modified: team/file/gulp_fax/res/res_sip_t38.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_t38.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_t38.c (original)
+++ team/file/gulp_fax/res/res_sip_t38.c Tue Jul 16 08:37:45 2013
@@ -70,19 +70,10 @@
 /*! \brief Address for IPv4 UDPTL */
 static struct ast_sockaddr address_ipv4;
 
-/*! \brief T.38 states for a session */                                                                                                                                                                                                          
-enum t38state {                                                                                                                                                                                                                              
-	T38_DISABLED = 0,     /*!< Not enabled */                                                                                                                                                                                            
-	T38_LOCAL_REINVITE,   /*!< Offered from local - REINVITE */                                                                                                                                                                          
-	T38_PEER_REINVITE,    /*!< Offered from peer - REINVITE */                                                                                                                                                                           
-	T38_ENABLED,          /*!< Negotiated (enabled) */                                                                                                                                                                                   
-	T38_REJECTED          /*!< Refused */                                                                                                                                                                                                
-};
-
 /*! \brief T.38 state information */
 struct t38_state {
 	/*! \brief Current state */
-	enum t38state state;
+	enum ast_sip_session_t38state state;
 	/*! \brief Our T.38 parameters */
 	struct ast_control_t38_parameters our_parms;
 	/*! \brief Their T.38 parameters */
@@ -133,7 +124,11 @@
 
 	data->session = session;
 	ao2_ref(session, +1);
-	data->frame = frame;
+
+	if (!(data->frame = ast_frdup(frame))) {
+		ao2_cleanup(data);
+		return NULL;
+	}
 
 	return data;
 }
@@ -159,16 +154,16 @@
 
 /*! \brief Helper function for changing the T.38 state */
 static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-	struct t38_state *state, enum t38state new_state)
-{
-	enum t38state old_state = state->state;
+	struct t38_state *state, enum ast_sip_session_t38state new_state)
+{
+	enum ast_sip_session_t38state old_state = session->t38state;
 	struct ast_control_t38_parameters parameters = { .request_response = 0, };
 
 	if (old_state == new_state) {
 		return;
 	}
 
-	state->state = new_state;
+	session->t38state = new_state;
 	ast_debug(2, "T.38 state changed to '%d' from '%d' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel));
 
 	if (!session->channel) {
@@ -242,12 +237,12 @@
 	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
 		/* Negotiation can not take place without a valid max_ifp value. */
 		if (!parameters->max_ifp) {
-			if (state->state == T38_PEER_REINVITE) {
-				/* XXX Need to reject their reinvite */
-			}
 			t38_change_state(data->session, session_media, state, T38_REJECTED);
+			if (data->session->t38state == T38_PEER_REINVITE) {
+				ast_sip_session_resume_reinvite(data->session);
+			}
 			break;
-		} else if (state->state == T38_PEER_REINVITE) {
+		} else if (data->session->t38state == T38_PEER_REINVITE) {
 			state->our_parms = *parameters;
 			/* modify our parameters to conform to the peer's parameters,
 			 * based on the rules in the ITU T.38 recommendation
@@ -265,8 +260,8 @@
 			state->our_parms.rate_management = state->their_parms.rate_management;
 			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
 			t38_change_state(data->session, session_media, state, T38_ENABLED);
-			/* XXX Need to accept their reinvite */
-		} else if (state->state != T38_ENABLED) {
+			ast_sip_session_resume_reinvite(data->session);
+		} else if (data->session->t38state != T38_ENABLED) {
 			if (t38_initialize_session(data->session, session_media)) {
 				break;
 			}
@@ -280,17 +275,19 @@
 	case AST_T38_TERMINATED:
 	case AST_T38_REFUSED:
 	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
-		if (state->state == T38_PEER_REINVITE) {
+		if (data->session->t38state == T38_PEER_REINVITE) {
 			t38_change_state(data->session, session_media, state, T38_REJECTED);
-			/* XXX Need to reject their reinvite */
-		} else if (state->state == T38_ENABLED) {
-			/* XXX Need to send reinvite */
+			ast_sip_session_resume_reinvite(data->session);
+		} else if (data->session->t38state == T38_ENABLED) {
+			/* XXX Need to unsupress other streams */
+			t38_change_state(data->session, session_media, state, T38_DISABLED);
+			ast_sip_session_refresh(data->session, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
 		}
 		break;
 	case AST_T38_REQUEST_PARMS: {		/* Application wants remote's parameters re-sent */
 		struct ast_control_t38_parameters parameters = state->their_parms;
 
-		if (state->state == T38_PEER_REINVITE) {
+		if (data->session->t38state == T38_PEER_REINVITE) {
 			parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
 			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
 			ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
@@ -314,9 +311,6 @@
 		if (!data) {
 			return f;
 		}
-
-		/* The frame is now on the task data structure */
-		f = &ast_null_frame;
 
 		if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) {
 			ao2_ref(data, -1);
@@ -423,33 +417,23 @@
 	.outgoing_request = t38_outgoing_invite_request,
 };
 
-/*! \brief Function which negotiates an incoming media stream */
-static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+/*! \brief Function which defers an incoming media stream */
+static int defer_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
 					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
 {
-	char host[NI_MAXHOST];
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
 	struct t38_state *state;
 	unsigned int attr_i;
 
 	if (!session->endpoint->t38udptl) {
-		return -1;
-	}
-
-	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
+		return 1;
 	}
 
 	if (t38_initialize_session(session, session_media)) {
-		return -1;
+		return 1;
 	}
 
 	if (!(state = t38_state_get_or_alloc(session))) {
-		return 0;
+		return 1;
 	}
 
 	for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
@@ -510,12 +494,49 @@
 
 	}
 
-	/* If we aren't the one who offered T.38 it is them, so change state */
-	if (state->state == T38_DISABLED) {
+	/* If they are initiating the re-invite we need to defer responding until later */
+	if (session->t38state == T38_DISABLED) {
 		t38_change_state(session, session_media, state, T38_PEER_REINVITE);
-	}
-
-	return 0;
+		return -1;
+	}
+
+	return 1;
+}
+
+/*! \brief Function which negotiates an incoming media stream */
+static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
+{
+	struct t38_state *state;
+	char host[NI_MAXHOST];
+	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+
+	if (!session->endpoint->t38udptl) {
+		return -1;
+	}
+
+	if (!(state = t38_state_get_or_alloc(session))) {
+		return -1;
+	}
+
+	if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
+		t38_change_state(session, session_media, state, T38_DISABLED);
+		return -1;
+	}
+
+	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
+
+	/* Ensure that the address provided is valid */
+	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
+		/* The provided host was actually invalid so we error out this negotiation */
+		return -1;
+	}
+
+	if (t38_initialize_session(session, session_media)) {
+		return -1;
+	}
+
+	return 1;
 }
 
 /*! \brief Function which creates an outgoing stream */
@@ -531,19 +552,20 @@
 	static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
 	static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
 	static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
+	struct t38_state *state;
 	pjmedia_sdp_media *media;
 	char hostip[PJ_INET6_ADDRSTRLEN+2];
 	struct ast_sockaddr addr;
-	struct t38_state *state;
 	char tmp[512];
 	pj_str_t stmp;
 
 	if (!session->endpoint->t38udptl) {
 		return 0;
+	} else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
+		(session->t38state != T38_ENABLED)) {
+		return 0;
 	} else if (!(state = t38_state_get_or_alloc(session))) {
-		return 0;
-	} else if ((state->state != T38_LOCAL_REINVITE) && (state->state != T38_PEER_REINVITE)) {
-		return 0;
+		return -1;
 	} else if (t38_initialize_session(session, session_media)) {
 		return -1;
 	}
@@ -675,6 +697,7 @@
 /*! \brief SDP handler for 'image' media stream */
 static struct ast_sip_session_sdp_handler image_sdp_handler = {
 	.id = "image",
+	.defer_incoming_sdp_stream = defer_incoming_sdp_stream,
 	.negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
 	.create_outgoing_sdp_stream = create_outgoing_sdp_stream,
 	.apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,




More information about the svn-commits mailing list